Update the object id of the object with generated Db ids in a disconnected environment (EF)

I am working with EF6 code first

in a project WinForm

. I used the following method to read objects from Db

, update them and then save them to Db

:

  • Reading an Entity graph using Linq to entities

    (after reading DbContext

    )
  • Show the read graph Entity

    to the end user.
  • The end user can apply these changes to the chart Entity

    :
    • Refresh root entity
    • Add child objects
    • Change some child objects
    • Remove some child objects
  • The user calls the method to save his changes to Db

  • Create a new instance DbContext

    .
  • Reload the same Entity

    graph fromDb

  • Map all property values ​​from the custom object to the reloaded object using AutoMapper

  • Attach the 6 steps result object to mine DbContext

    withGraphDiff

  • Call DbContext.SaveChanges();

    to save changes toDb

    enter image description here

    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 great,

In the second graph, Child13 and Child22 are added by the user, and when I call uow.SaveChanges()

they will persist before Db

and they Id

will be assigned. but Child13.Id

also Child22.Id

into Entity

objects 0

, but I could manually update Id

, but I'm looking for a generic way to update these values Id

with the Db

generated Id

s.

+3


source to share


1 answer


Personally, I would take a slightly different approach.

A transaction like this does not need to span multiple contexts. Even though you can manually update these ids, you will need some alternative way to identify these child objects to ensure that you synchronize the object instance correctly with the identifier assigned by your database. Or it is possible that other aspects of these objects were updated during the transition and would need to apply to the database as well. Generally speaking, objects loaded from different DBC contexts are different objects, even if they have the same database id, unless you've implemented some sort of caching on top of EF.

I would do something like this. Use one context and let EF manage all of your identifying information by introducing the context where you need to perform save 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 for some reason you cannot use the same context, you may want to add an additional identification field to the child object, for example, Guid, and write this to the child before, in the database via SaveChanges. At the very least, you will have a fairly consistent means of identifying objects to synchronize.

+3


source







All Articles