Reputation: 8181
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
:
Linq to entities
(after reading the DbContext
disposes)Entity
graph to end user.Entity
graph:
Db
DbContext
instance.Entity
's graph from Db
AutoMapper
DbContext
using GraphDiff
Call DbContext.SaveChanges();
to persist changes to Db
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 Id
s will be assign. but Child13.Id
and Child22.Id
in entity
objects are 0
yet, I could manually update the Id
s but I'm looking for generic way to update these Id
values with Db
generated Id
s.
Upvotes: 3
Views: 895
Reputation: 1249
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:
var context = new MyDbcontext();
var root = context
.Roots
.LoadAggregation()
.ToList();
// LoadAggregation in this case, means following codes:
// .Include("Child1")
// .Include("Child2")
root.Child1.Remove(child11);
root.Child1.Add(Child13); //
root.Child2.Add(Child22);
using(var uow = new UnitOfWork())
{
uow.Repository<Root>().Update(root, context);
uow.Repository<AnotherRoot>().Update(anotherRoot, context); //user may want to update multiple Roots
uow.SaveChanges(context); <---- at this point Child13.Id and Child22.Id generated by Db
}
public void Update(Root entity, MyDbcontext context) //Update method in my Repository class
{
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(context) // SaveChanges() in UnitofWork class
{
context.SaveChanges();
}
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.
Upvotes: 3