I want to use the EF Core HasData method to seed a database with reference data. Two of the models I want to seed follow the Table per Hierarchy (TPH) pattern in the sense that there is a none abstract base type and another none abstract derived type. These models in the database exist in a table named after the base type with a discriminator column. I would like to add data seeding for this table. However I’m struggling to find any guidelines of how to do so in the EF Core 6 documentation.
I have a few related questions:
Do I seed all the data using the HasData method on an EntityTypeBuilder<BaseType> or do I need to split the seeding into one HasData on that class and another on EntityTypeBuilder<DerivedType>?
I understand using TPH will add a shadow discriminator property and that, potentially, I’ll have to add that in the data seeding. Does that mean I have to use anonymous types to specify that property (doesn’t seem very elegant) and if so, can I get the autogenerated discriminator name using a method (typing it manually sounds like a risk as what if EF Core changes the discriminator name convention?)?
Should I be avoiding using TPH on reference tables altogether? Is there something else I should do instead?
After going through my options with trial and error, I have come to the following solution. It may not be perfect, but it deals with all of my concerns.
Do I seed all the data using the HasData method on an EntityTypeBuilder<BaseType> or do I need to split the seeding into one HasData on that class and another on EntityTypeBuilder<DerivedType>?
You have to do it on both classes, attempting otherwise throws on creating the migration:
The seed entity for entity type 'BaseType' cannot be added because the value provided is of a derived type 'DerivedType'. Add the derived seed entities to the corresponding entity type.
I understand using TPH will add a shadow discriminator property and that, potentially, I’ll have to add that in the data seeding. Does that mean I have to use anonymous types to specify that property (doesn’t seem very elegant) and if so, can I get the autogenerated discriminator name using a method (typing it manually sounds like a risk as what if EF Core changes the discriminator name convention?)?
I have added a property to the BaseType class and defined it as the discriminator, so now I can specify the discriminator values directly without using anonymous type and I am in control of the discriminator values. Gert Arnold points out in this other answer why this might not be appropriate. However I have used the following method described in this EF Core Github issue to hopefully mitigate the concerns he raised.
Should I be avoiding using TPH on reference tables altogether? Is there something else I should do instead?
This is still unanswered. But I am feeling a lot more confident it is a good approach now.
Related
I have a database model that can be modify by users at runtime:
adding new columns to existing tables
adding new tables
I want to use Entity Framework Core to access such model.
I'm able of creating the types for the new tables and fields using reflection but I'm not able of creating the DbSet members inside the DbContext class for these new types as the DbSet needs to know the type at compile time.
Does anyone know if this is something that can be achieved with EF Core?
A way of injecting the type to the DbSet member dynamically?
It sounds pretty weird to me that the users are the ones defining the tables and their columns, relationships, etc on runtime. Probably what you actually need is to have a structure of tables to support dynamic data, which is much more manageable, that is, a table that defines the UserModels, another table that defines the properties of those models, etc. That will vary a lot depending on your needs.
You could also consider using some special properties like XML data-type fields as suggested here: Dynamically adding a property to an entity framework object
trying to implement table per concrete type using model first, but when saving the derived type, EF saves to both the base and derived tables. how do you configure EF to save the type to the correct corresponding table?
There is a good discussion of choosing an approach here that recommends against TPC for Entity Framework: http://blogs.msdn.com/b/alexj/archive/2009/04/15/tip-12-choosing-an-inheritance-strategy.aspx
For this reason: While the EF runtime supports TPC, the designer doesn't, and using TPC in the EF forces you to avoid associations in your base type. Because of these issues we generally discourage the use of TPC with the Entity Framework.
My best guess is that if you are writing to a base and derived tables as your problem you have tried to implement this where you have a concrete class which is extended by an additional concrete class? As per the discussion above, the simple answer is TPC will not work like this for EF (the referenced article is 2009, but I don't think this has changed).
I have the below scenario. I am using EF 5 Code first, MVC 4 on VS 2010. I am using the Unit of Work and Repository pattern for my project.
I am not sure if this is possible or not. Kindly suggest.
I have a model class representing a database table. In the model class, I have a property that is decorated as [NotMapped]. I have a Stored Proc that returns data, similar to the model class. However, when I get the data in a List from the SP, it does not contain value for the [NotMapped] column (SP returns data for the [NotMapped] column though). This may be logically correct with respect to EF.
All I want to know is, do we have a way to get data populated for the [NotMapped] column. I want to achieve, CRUD using LINQ (excluding R - Read).
I would recommend to create a separate complex type for the stored procedure results. Otherwise sooner or later you will find yourself writing code to distinguish between entities coming from the DbSet or from the stored procedure. When the come from the stored procedure they can't be used in joins, for example. Or checks whether or not the unmapped property is set.
A very dirty approach could be to have two different contexts. With code first it is possible to have different contexts with different mappings to the same types, with and without the column ignored (if you use fluent mapping, not with data annotations). But that only succeeds if you tell EF not to check the database schema, so using migrations is ruled out as well. I would not do it!! For the same reason as I mentioned above. I would hate to have a type with a property that sometimes is and sometimes isn't set.
I understand that, when working with POCO entities, you should work against your model (POCO Entities). Also I supose that part of the benefits of programming against models like those should provide benefits like defining classes that don't match exactly what you see in the db.
However, there are simple operations that I don't know how to do and that I assume they should be possible. For example, in some scenarios it can be useful to change the name of one column (atribute in the entity). Also I would like to know if it's possible to generate POCO models that only represents some fields of the table that supports the object in the db.
Is there any documentation about this kind of operations?
¡Thanks a lot!
POCO entity is just mapped class. The model in your question means mapping. The point of mapping is to define map between class and database table including mapping between properties and columns. So you can have different property and column names as long as it is correctly configured in mapping.
So if you are using EDMX file (designer) for generating the mapping you can simply change the name of property or entity and it will be reflected in your generated POCO entity. Also EDMX file will correctly update mapping. If you are using code first you must manually define mapping either through data annotations or through fluent API.
Entity should represent single data structure persisted to the database. Because of this each table can be mapped only once. Moreover EDMX designer demands that each non-nullable column without default value must be mapped to the entity. POCO generator is not tool for generating your different data views. What you are looking for is called projection. There are ways how to include mapped projections in EDMX file (DefiningQuery and QueryView) but both requires manual modifications of EDMX file and the first one also requires manual maintenance of EDMX file.
If you need to remove some properties from entity just to improve some query or because you don't need all data for some operation you can always use projection to anonymous or custom class directly in the query.
var query = from x in context.XEntities
select new XView
{
A = x.A,
B = x.B
};
POCO generator is only tool for generating classes for mapped entities and projections not for generating all data related classes you will ever need.
For part of the project I'm currently working on, I have a set of four tables for syndicatable actions. One table is the abstract base for the other three, and each table is represented in my EF model like so:
EF Model -- Actions http://chris.charabaruk.com/system/files/images/EF+Model+Actions.png
There are two problems that I'm currently facing with this, however. The first problem is that Actor (a reference to a User) and Subject (a reference to an entity of the class associated with each type of action) are null in my subclasses, despite the associated database columns holding valid keys to rows in their associated tables. While I can get the keys via ActorReference and SubjectReference this of course requires setting up a new EF context and querying it for the referenced objects (as FooReference.Value is also null).
The second problem is that the reciprocal end of the relationship between the concrete action classes and their related entity classes always turn up nothing. For example, Task.RelatedActions, which should give me all TaskAction objects where Subject refers to the particular task object on which RelatedActions is called, is entirely devoid of objects. Again, valid rows exist in the database, Entity Framework just isn't putting them in objects and handing them to me.
Anyone know what it is I'm doing wrong, and what I should do to make it work?
Update: Seems that none of the relationship properties are working in my entity model any more, at all. WTF...
I think the issue you are experiencing here is that by default the EF does not automatically load related entities. If you load an entity, the collection or reference to related entities will be empty unless you do one of the following things:
1) Use eager loading in order to retrieve your main entity and your related entity in a single query. To do this, modify your query by adding a call to the Include method. In your sample above, you might use the following query:
from a in context.Actions.Include("Actor") select a
This would retrieve each of the actions with the related Actor method.
2) Use explicit lazy loading to retrieve the related entity when you need it:
action1.ActorReference.Load()
In the version of the EF which will ship with .Net 4.0, you will also have the following additional option:
3) Turn on implicit lazy loading so that related entities will automatically be retrieved when you reference the navigation property.
Danny