Microsoft Developer Network >
Forums Home
>
Data Platform Development (Pre-release) Forums
>
ADO.NET Entity Framework and LINQ to Entities (Pre-Release)
>
Creating/Updating entities with complex relationships
Creating/Updating entities with complex relationships
- Hi,
Having migrated our projects to VS 2010 Beta2, we are trying the EF 4.0 as orm for the DAL, and have the following scenario:
Based on our own DSL, we are generating, besides other components, the following elements relevants for the question:
1. Database scripts.
2. Business Entities (POCOs). For this purpose, let's assume as simple classes with getters and setters.
3. EF files (ssdl, csdl, and msl).
4. Classes that inherit from from ObjectContext, storing ObjectSet's for each entities.
We can successfully create and update simple entites with the following code (example for a Product object):In this case, products is of type ObjectSet<Product>.public void CreateProduct (Product instance) { products.Attach(instance); ObjectStateManager.ChangeObjectState(instance, EntityState.Added); products.AddObject(instance); this.SaveChanges(); } public void UpdateProduct (Product instance) { products.Attach(instance); ObjectStateManager.ChangeObjectState(instance, EntityState.Modified); products.ApplyCurrentValues(instance); this.SaveChanges(); }
The problems start when the objects are more complex. For example, in a master-detail scenario (ex: Order-OrderDetails), we are getting the following error:
"An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key".
It occurs in the line of the Attach method, as the example above (in that case invoices.Attach(instance); )
As we are new with EF, we are not really sure about if this is the better way to implement these Create/Update methods. Also, and as I could understand, it seems to be something related with self-tracking entities, and have read about the Entity Framework Feature which is still not shipped for VS 2010 Beta2.
So, the question is, is this the right way to do the job and what is missing for these scenarios? Does the EF Feature CTP effectively the best way to handle this?
Many thanks in advance.
paulo
Answers
- Hi Paulo,
I run through the same problem, here's the solution:
You have to attach, and then manually change the object state. More info can be found in the ADO.Net blog:public Product AddNewProduct(Product prod) { try { using (var ctx = new NorthwindContext()) { ctx.Products.Attach(prod); ctx.ObjectStateManager.ChangeObjectState( prod, System.Data.EntityState.Added); ctx.ObjectStateManager.ChangeObjectState( prod.Category, System.Data.EntityState.Unchanged); ctx.SaveChanges(); } } catch (Exception exp) { // Do something meaningful here<br/> string msg = exp.Message; } return prod; }
http://blogs.msdn.com/efdesign/archive/2008/11/20/n-tier-improvements-for-entity-framework.aspx (see Attach extension method)
With Beta 2 + CTP 2 you have self tracking entities that does this behind the scenes for you.
HTH,
Carlos- Edited byElArquitecto Tuesday, November 24, 2009 5:00 AMedit code
- Marked As Answer bypaulobraga Tuesday, November 24, 2009 9:18 AM
All Replies
- I'd need to see more code and exceptions to understand what is going on, but one comment:
In CreateProduct, you do not need to call Attach and ChangeObjectState, you just need to call products.AddObject. This may be why you are seeing issues: AddObjects essentially does what the previous two lines do.
This posting is provided "AS IS" with no warranties, and confers no rights. - Hi, Noam.
Thanks for your response.
Regarding you suggestion, If I try to call the AddObject method directly, it seems to try to perform an insert in a FK table (when i just want to refer a record from a FK entity in a business object).
Concerning our scenarios, we also have implemented an inheritance mechanism for our generated business entities (with, besides other stuff, an Id is defined in a base entity). The Id is then defined as the Key element in the mapping files. As I could meanwhile undertood since the first post, it seems that the error may be related with this fact, whenever I try to insert more that one line in a child entity.
I have already realized that we will have to implement the tracking changes, as the sample posted in the EF Team blog, but the CTP for EF Feature is not yet available for VS 2010 Beta2.
I would like to send you a simple project with a simplified scenario based on our generated artifacts, with this issue reproduced, so you can analyze it.
How can I send you the project?
Many thanks.
Paulo. - Looking at EF Feature CTP2, but still not found solution for the error on the Attach method...
Paulo. - Hi,
After some additional analysis, i've found the following (isolated scenario):
3 entities: Invoice, InvoiceLine, and Product.
Invoice and InvoiceLine are related by master/detail, and Product is a foreign entity of InvoiceLine.
All these entities have an Id (Guid) defined as key.
For test purposes, i use the same product in the lines, simple as:
for (int i = 1; i <= lines; i++) { InvoiceLine invoiceLine = CreateInvoiceLine(i); invoice.InvoiceLines.Add(invoiceLine); }
and the invoice line is created with the following code:
The error is raised whenever I try to create an Invoice object with more than 1 line, and when the Product is obtained using a different context object.private static InvoiceLine CreateInvoiceLine(int line) {<br/> using (PersistenceConceptEntities context = new PersistenceConceptEntities())<br/> { Product product = context.Products.FirstOrDefault(p => p.Code == "001"); } <br/> InvoiceLine invoiceLine = new InvoiceLine(); invoiceLine.Id = Guid.NewGuid(); invoiceLine.Product = product; invoiceLine.UnitPrice = 10 * line; return invoiceLine;<br/> }<br/><br/>
Since I'm just trying to refer the same product in different lines, and presuming that the final Invoice instance will arrived in a dettached state, has anyone any idea?
Thanks.
Paulo. - Hi Paulo,
I run through the same problem, here's the solution:
You have to attach, and then manually change the object state. More info can be found in the ADO.Net blog:public Product AddNewProduct(Product prod) { try { using (var ctx = new NorthwindContext()) { ctx.Products.Attach(prod); ctx.ObjectStateManager.ChangeObjectState( prod, System.Data.EntityState.Added); ctx.ObjectStateManager.ChangeObjectState( prod.Category, System.Data.EntityState.Unchanged); ctx.SaveChanges(); } } catch (Exception exp) { // Do something meaningful here<br/> string msg = exp.Message; } return prod; }
http://blogs.msdn.com/efdesign/archive/2008/11/20/n-tier-improvements-for-entity-framework.aspx (see Attach extension method)
With Beta 2 + CTP 2 you have self tracking entities that does this behind the scenes for you.
HTH,
Carlos- Edited byElArquitecto Tuesday, November 24, 2009 5:00 AMedit code
- Marked As Answer bypaulobraga Tuesday, November 24, 2009 9:18 AM

