【问题标题】:Entity Framework 6 deep copy/clone of an entity with dynamic depthEntity Framework 6 深度复制/克隆具有动态深度的实体
【发布时间】:2016-02-25 19:23:54
【问题描述】:

我正在尝试深度克隆/复制包含相同类型子项的实体项。该项目也有参数,也应该被克隆。然而,ItemType 应该作为对现有 ItemType 的引用。

图解:

在 Stackoverflow (Entity Framework 5 deep copy/clone of an entity) 的帮助下,我提出了以下相当糟糕的尝试:

public Item DeepCloneItem(Item item)
{
    Item itemClone = db.Items //Level 1
        .Include(i => i.ChildrenItems.Select(c => c.ChildrenItems )) //3 Levels
        .Include(i => i.Parameters) //Level 1 Params
        .Include(i => i.ChildrenItems.Select(c => c.Parameters)) //Level 2 Params
        .Include(i => i.ChildrenItems.Select(c => c.ChildrenItems
            .Select(cc => cc.Parameters))) //Level 3 Params
        .AsNoTracking()
        .FirstOrDefault(i => i.ItemID == item.ItemID);
    db.Items.Add(itemClone);
    db.SaveChanges();
    return itemClone;
}

对于 3 的固定深度级别,此尝试就像一个魅力。但是,正如您所看到的,这在每个更深层次上都不是很好。该设计允许无限数量的嵌套(但在我的上下文中,不应超过 5 层)。

是否有可能根据最大深度将 Includes 动态添加到 IQueryable 中?

这是要克隆的项目实体:

public class Item
{
    public int ItemID { get; set; }

    public int? ParentItemID { get; set; }
    [ForeignKey("ParentItemID")]
    public virtual Item ParentItem { get; set; }
    public virtual ICollection<Item> ChildrenItems { get; set; }

    [InverseProperty("Item")]
    public virtual ICollection<Parameter> Parameters { get; set; }

    public ItemTypeIds ItemTypeID { get; set; }
    [ForeignKey("ItemTypeID")]
    public virtual ItemType ItemType { get; set; }
}

【问题讨论】:

    标签: c# .net entity-framework linq entity-framework-6


    【解决方案1】:

    我找到了一种更通用的方法来解决这个问题。 对于可能遇到类似问题的任何人,这是我现在解决的方法:

    public Item DeepCloneItem(Item item)
    {
        Item itemClone = db.Items.FirstOrDefault(i => i.ItemID == item.ItemID);
        deepClone(itemClone);
        db.SaveChanges();
        return itemClone;
    }
    
    private void deepClone(Item itemClone)
    {
        foreach (Item child in itemClone.ChildrenItems)
        {
            deepClone(child);
        }
        foreach(Parameter param in itemClone.Parameters)
        {
            db.Entry(param).State = EntityState.Added;
        }
        db.Entry(itemClone).State = EntityState.Added;
    }
    

    请记住,递归调用必须在 EntityState.Added 分配之前。否则,递归将停止在第二级。 此外,递归方法必须调用处于 Attached 状态的实体。否则,递归也将停止在第二层。

    如果您的实体树非常深,请考虑用迭代方法替换递归。欲了解更多信息,请查看:Wikipedia Recursion versus iteration

    欢迎反馈和改进!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      • 2017-09-01
      • 1970-01-01
      • 2014-06-22
      • 1970-01-01
      相关资源
      最近更新 更多