【问题标题】:What is the proper way to update child entities in EF 6?在 EF 6 中更新子实体的正确方法是什么?
【发布时间】:2015-06-03 18:35:53
【问题描述】:

必须有更好的方法来处理 EF 6 中的子保存/更新。当然,这种重复只是我的失败。

实体

public partial class MyParentType
{
    public MyParentType()
    {
        this.children = new HashSet<child>();
    }

    public int parentID { get; set; }

    public virtual ICollection<child> children { get; set; }
}

添加/更新

public class MyRepository : IMyRepository
{
    private readonly IErrorLogger _logger;
    private readonly CorporateEntities _context;

    public MyRepository(IErrorLogger logger)
    {
        _logger = logger;
        _context = new CorporateEntities();
    }

    public void Update(IEnumerable<MyParentType> parents)
    {
        try
        {
            Add(parents.Where(x => x.parentID == 0));
            var updatedData = parents.Where(x => x.parentID != 0);
            foreach (var parent in updatedData)
            {
                var original = _context.MyParentTypes.FirstOrDefault(x => x.parentID == parent.parentID);
                _context.Entry(original).CurrentValues.SetValues(parent);
                UpdateChildren(parent);
            }
            _context.SaveChanges();
        }
        catch (Exception exception)
        {
            _logger.Error(exception.Message, exception);
        }
    }

    public void Add(IEnumerable<MyParentType> parents)
    {
        if (parents == null)
            return;
        try
        {
            _context.MyParentTypes.AddRange(parents);
            _context.SaveChanges();
        }
        catch (Exception exception)
        {

            _logger.Error(exception.Message, exception);
        }
    }

    private void UpdateChildren(MyParentType parent)
    {
        try
        {
            AddChildren(parent.children.Where(x => x.childID == 0));
            var updatedData = parent.children.Where(x => x.childID != 0);
            foreach (var child in updatedData)
            {
                var original = _context.children.FirstOrDefault(x => x.childID == child.childID);
                _context.Entry(original).CurrentValues.SetValues(child);
            }
            _context.SaveChanges();
        }
        catch (Exception exception)
        {

            _logger.Error(exception.Message, exception);
        }
    }

    private void AddChildren(IEnumerable<child> references)
    {
        try
        {
            _context.children.AddRange(references);
            _context.SaveChanges();
        }
        catch (Exception exception)
        {

            _logger.Error(exception.Message, exception);
            throw;
        }
    }

}

我觉得我不应该复制这个或编写一个通用方法来处理这两种情况。我是否错过了 EF 文档中的某些内容,我可以在其中使用父实体更新子实体?

【问题讨论】:

标签: c# entity-framework


【解决方案1】:

我建议您使用GraphDiff。有了这个library,您的Update 方法将如下所示:

 public void Update(IEnumerable<MyParentType> parents)
 {
   try
   {
       Add(parents.Where(x => x.parentID == 0));
       var updatedData = parents.Where(x => x.parentID != 0);
       foreach (var parent in updatedData)
       {
          _context.UpdateGraph(parent, map => map.OwnedCollection(p => p.children));   
       }
       _context.SaveChanges();
   }
   catch (Exception exception)
   {
     _logger.Error(exception.Message, exception);
   }
}

这样你就不用担心管理孩子的状态了。

如果你不想使用 GraphDiff,那么你需要手动管理孩子的状态:

 public void Update(IEnumerable<MyParentType> parents)
 {
   try
   {
       foreach (var parent in parents)
       {
         if(parent.Id==0)
         {
          _context.MyParentTypes.Add(parent);
         }
         else
         { 
            //When you change the state to Modified all the scalar properties of the entity will be marked as modified
           _context.Entry(parent).State = EntityState.Modified;

            foreach(var child in parent.children)
            {
               context.Entry(child).State =child.Id>0? EntityState.Modified:EntityState.Added;  
            }
         }
       }

       _context.SaveChanges();
   }
   catch (Exception exception)
   {
     _logger.Error(exception.Message, exception);
   }
}

【讨论】:

  • 使用 GraphDiff,您仍然可以显式地绘制每个孩子的图表(参见代码的第 9 行)?
  • 还有,住宿应该是小孩吗?
  • 是的,但是您不必自己管理每个孩子的状态,此外,GraphDiff 可以让您在图的更深层次上更新相关实体。例如,如果 child 有另一个实体 (ICollection&lt;AnotherEntity&gt; AnotherEntities) 的集合,那么您可以这样更新图表:context.UpdateGraph(parent, map =&gt; map.OwnedCollection(p =&gt; p.children, with =&gt; with.OwnedCollection(c =&gt; c.AnotherEntities)));
  • 很公平,这似乎是一个不错的权衡
  • @octavioccl 您的手动方法不处理已删除的子项?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多