ADO.NET Entity Framework Hierarchy type Inheritance Error 3032 Workaround? - entity-framework

I would like to implement a Hierarchy Type Inheritance ... i.e. Cars to BMWs ... Cars would have CarTypeID that is associated with CarTypes. I would like CarTypeID to be the discriminator column. Unfortunately, I cannot do this in ADO.NET Entity Framework.
If I would like to keep the association, how am I able to achieve this?
Has anyone come up with a work around?

You can't do this. You must use a different column, as the column which is a constrained FK end and the inheritance discriminator column cannot be the same.
I'm of mixed minds as to whether this is a bad thing or not. I think inheritance is often overused, especially in O/R modeling. If you already have a FK to car type info...

Related

EF Core HasData Seeding a TPH Entity

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.

How does EF tell apart TPC and TPT inheritance models?

For Table Per Concrete Type model the whole entity is stored as a row in one table.
For Table Per Type additional tables contan only specific to descendant type data.
If the forst case EF issues one insert, and in the second one it must issue two inserts: for base and for inherited types' tables.
I cannot understand how EF knows what to do. The only difference I see now is just mappings in MSL: either they overlap or not.

How should I map relationships between multiple inheritance models?

I have an Eentity Framework model with a Table Per Hierarchy (Brand) and also a Table Per Type (Vehicle) inheritance like this:
(Vehicle and Brand are abstract classes).
So far so good, I can access derived entities on linq queries using Vehicle.OfType<> or Brand.OfType<> method.
Now, Brand entity is one to many related with Vehicle on my conceptual model, So the question is, how should I make relationships on EF model so I can keep using navigation properties between Vehicle and Brand but at the same time keep the consistency of the TPH inheritance on Brand?, my first approach was to relate only derived clases, like:
But if I do this, I have no access to Brand directly from Vehicle, so I would have to do a double relation (between derived and base), like:
This works for me now, but I still have a duplicated relationship somehow, is this right?, do you have a better approach?, am I'm making some silly mistake on my modelling?
It seems to me that the reason you are running into cross-linking in your model is because you are artificially separating Brand and Vehicle as top-level sibling entities. If you start with Brand, which seems essentially equivalent to Make, that becomes the true top-level entity. There is no need to separate Make for each vehicle type (car, motorcycle, truck, etc.); just introduce the entity Model between Make and Vehicle and I think that solves most of your cross-linking problems.
Then the relationships aren't strictly parent-child, but are more accurate as composition. So you have Make, which has a one-to-many composite relationship to Model, which in turn has a one-to-many composite relationship to Vehicle. Vehicles are instances of a Model, so there isn't really a parent-child relationship there either. With this structure, there is no need to branch the EF for each type of Vehicle, because that is just part of what is described by the Model entity.
I hope my answer is helpful and that I haven't missed any of the essential points of what you are trying to model-

Entity Framework Inheritance

Have a scenario with a client's new crm where they have suppliers and clients and a supplier is also a client and vice versa. Table per hierarchy will only allow a person to only be one or the other, so I assume table per type would be better suited.
The db structure would be:
[Contact]
ContactId pk
Name
...
[Client]
ContactId pk / fk
VATNumber
...
[Supplier]
ContactId pk / fk
...
Anyone have any other suggestions or experience from a similar scenario?
Table per type will also assume one Contact is either a client or a supplier (this is clearer if you look at the generated SQL: eg. see "Inheritance with EF Code First CTP5: Part 2 – Table per Type (TPT)").
Instead I think you need to change your model to be Contact and Contact-Role with a one to many relationship. Contact-Role would have the Supplier and Client subtypes. The whole Contact-Role hierarchy could then be mapped as TPH or TPT.
This reflects an OO design where each client has one or more roles (inheritance, "is-a" releationship, will always be singular, you cannot have an object of abstract type client that is simultaneously both subtypes of client).
This cannot work unless you model it as three level inheritance which would require that either client is always supplier or supplier is always client. I guess that is not correct model in your application which means you cannot use inheritance.
You have to either use one-to-one (0..1-1) relations between contact-client and contact-supplier or you can simply place all properties to single table and add IsClient and IsSupplier bit columns - it is not very nice and it is less extensible but it is very easy to use. These two bit columns can be useful in case of relational representation as well.

Unable to specify abstract classes in TPH hierarchy in Entity Framework 4

I have a TPH heirachy along the lines of:
A->B->C->D
A->B->C->E
A->F->G->H
A->F->G->I
I have A as Abstract, and all the other classes are concrete with a single discriminator column.
This works fine, but I want C and G to be abstract also. If I do that, and remove their discriminators from the mapping, I get error 3034 'Two entities with different keys are mapped to the same row'. I cannot see how this statement can be correct, so I assume it's a bug in some way.
Is it possible to do the above?
Lee
Seeing as they are abstract - so there are no entities in the database - have you tried just lying and pretending they do have a discriminator.
This should satisfy the mapping, but since the classes are abstract you still won't be able to create or materialize.
Alex