Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 4: Table per Type inheritance problem on insert

I have simple model with a "BaseEntity" and a derived "Fund" entity. When I try to insert a new fund:

HybridModelContainer container = new HybridModelContainer();

//Create new Fund
Fund fund = new Fund();
fund.Id = Guid.NewGuid();
fund.DateCreated = DateTime.Now;
fund.Name = "Fund 1";
fund.Number = 1;
container.BaseEntities.AddObject(fund);

container.SaveChanges();

I get the following error:

"Cannot insert the value NULL into column 'Id', table 'HybridData.dbo.BaseEntities'; column does not allow nulls. INSERT fails.
The statement has been terminated."

It seems that the ID assigned to the fund entity is not inserted into the BaseEntity table. Why not?

I did this "model first". If I design the database first, and create the model from it, everything works fine....But I need model first!

enter image description here

Also...why isn't there an ObjectSet for "Funds" in my DataContext (i.e., container.Funds)? Thanks in advance for your help!

like image 865
SolarX Avatar asked Feb 23 '11 13:02

SolarX


1 Answers

I can only answer for the second part of your question: "Also...why isn't there an ObjectSet for "Funds" in my DataContext (i.e., container.Funds)?"

It's normal that the ObjectContext has only an ObjectSet of the base class in your class hierarchy. There isn't really a need for an ObjectSet of the derived classes. For adding and deleting derived objects to/from the ObjectContext you can just use the AddObject and DeleteObject methods of the ObjectSet<BaseEntity> / BaseEntities as you already did in your example.

For querying derived objects you can leverage the OfType method of the ObjectSet. It returns an ObjectQuery of the derived type where you can build further queries upon:

ObjectQuery<Fund> query = container.BaseEntities.OfType<Fund>();

(The first part of your question sounds like a mapping error between the storage and the conceptual model. It might have a better cif you could show the relevant parts of your edmx file.)

Edit: Possible solution to the first part of the question:

I've created your example with Model-first in VS2010 and I could reproduce your issue. The problem seems to be related to the fact that the primary key in your model isn't an Int32 but a Guid. When you add a new Entity to the Model the designer always proposes an Int32 as primary key with StoreGeneratedPattern set to Identity.

If you change now the type of the key in the model designer from Int32 to Guid but leave the StoreGeneratedPattern unchanged being Identity, the DDL creates a database in SQL Server with Id set to type uniqueidentifier but Identity specification for that column is "No".

So, when EF sends an INSERT command to the DB it "thinks" from the model definition the primary will be autogenerated in the DB and doesn't send the Guid to the DB which you have assigned in code. But the DB doesn't create the key, resulting in a NULL value for the key. Hence the error we get.

Solution: Set in the model designer for the Id property of BaseEntity the StoreGeneratedPattern to None. For me it worked then. Of course, you are responsible then to always assign a Guid to Id before you add a new object to the ObjectSet, but that seems to be what you want anyway.

like image 153
Slauma Avatar answered Oct 17 '22 03:10

Slauma