在Disconnected environment(EF)中使用Db生成的ID更新实体图Ids

时间:2014-08-06 07:45:22

标签: c# entity-framework ef-code-first repository graphdiff

我在EF6 code first项目中使用WinForm。 我使用以下方法从Db读取实体,更新它们,然后将它们保存到Db

  1. 使用Linq to entities阅读实体图表(阅读DbContext处置后)
  2. 向最终用户显示已知的Entity图表。
  3. 最终用户可以将此更改应用于Entity图表:
    • 更新根实体
    • 添加一些子实体
    • 编辑一些子实体
    • 删除一些子实体
  4. 用户调用方法将其更改保留到Db
  5. 创建新的DbContext实例。
  6. Entity
  7. 重新加载相同的Db图表
  8. 使用AutoMapper
  9. 将所有属性的值从用户实体映射到重新加载的实体
  10. 使用DbContext
  11. 将6步结果实体附加到我的GraphDiff
  12. 致电DbContext.SaveChanges();将更改保留为Db 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
    }
    

  13.     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();
        }
    

    一切正常,

    在第二张图中,用户添加了Child13和Child22,当我致电uow.SaveChanges()时,他们将保存到Db,并且将分配他们的Id。但Child13.Id对象中的Child22.Identity仍为0,我可以手动更新Id,但我正在寻找通用通过Id生成Db来更新这些Id值的方法。

1 个答案:

答案 0 :(得分:3)

就个人而言,我采取的方法略有不同。

这样的交易不应该跨越多个上下文。即使您可以手动更新这些ID,您也需要某种替代方法来识别这些子对象,以确保您使用数据库分配的ID正确同步对象实例。或者它可能在瞬态时更新这些对象的其他方面,并且还需要应用于数据库。一般来说,从不同的DBContexts加载的对象是不同的对象,即使它们具有相同的数据库标识,除非您在EF之上实现了某种缓存。

我做这样的事情。使用一个上下文,让EF通过注入需要执行持久性操作的上下文来管理所有标识:

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();
}

如果由于某种原因您无法使用相同的上下文,您可能需要考虑在子对象(例如Guid)中添加某种其他标识字段,然后将其写入子对象之前通过SaveChanges持久回到数据库。至少你有一个相当一致的方法来识别同步对象。