I'm working with EF6 code first in a WinForm project.
I used following method for reading entities from Db, updating them and then save back them to Db:
- Read Entity graph using
Linq to entities(after reading theDbContextdisposes) - Show readed
Entitygraph to end user. - End user may apply this changes to
Entitygraph:- Update root entity
- Add some child entities
- Edit some child entities
- Delete some child Entities
- User call a method to persist his changes to
Db - Create a new
DbContextinstance. - Reload same
Entity's graph fromDb - Map the all property's value from user entity to reloaded entity using
AutoMapper - Attach the result entity of 6 step to my
DbContextusingGraphDiff Call
DbContext.SaveChanges();to persist changes toDb
var root = new MyDbcontext() .Roots .LoadAggregation() .ToList(); // LoadAggregation in this case, means following codes: // .Include("Child1") // .Include("Child2") root.Child1s.Remove(child11); root.Child1.Add(Child13); // root.Child2.Add(Child22); using(var uow = new UnitOfWork()) { uow.Repository<Root>().Update(root); uow.Repository<AnotherRoot>().Update(anotherRoot); //user may want to update multiple Roots uow.SaveChanges(); <---- at this point Child13.Id and Child22.Id generated by Db }
public void Update(Root entity) //Update method in my Repository class
{
var context = new MyDbcontext();
var savedEntity = context.Roots //reload entity graph from db
.LoadAggregation()
.ToList();
Mapper.Map(entity,savedEntity); // map user changes to original graph
context.UpdateGraph(savedEntity, savedEntity.MappingConfiguration); // attach updated entity to dbcontext using graphdiff
}
public void SaveChanges() // SaveChanges() in UnitofWork class
{
context.SaveChanges();
}
It works fine,
In second graph the Child13 and Child22 added by user and when I call uow.SaveChanges() they will save to Db and their Ids will be assign. but Child13.Id and Child22.Id in entity objects are 0 yet, I could manually update the Ids but I'm looking for generic way to update these Id values with Db generated Ids.
Personally, I'd take a slightly different approach.
A transaction like this shouldn't span multiple contexts. Even if you could update those ID's manually, you'd need some sort of alternate way of identifying those child objects to ensure you synced up the object instance correctly with the ID assigned by your database. Or it's possible other aspects of those objects were updated while transient, and will need to be applied to the database as well. Generally speaking, objects loaded from different DBContexts are different objects, even if they have the same database identity unless you've implemented some sort of caching on top of EF.
I'd do something like this. Use one context, and let EF manage all of the identify for you by injecting the context where you need to do persistence operations:
If you're unable to use the same context for some reason, You may want to consider adding an additional identity field of some sort to the child object, such as a Guid, and writing that to the child prior to persisting back to the database via SaveChanges. At least you'd have a fairly consistent means of identifying the objects for syncing.