2015-11-23 17 views
6

同じタイプの子アイテムを含むエンティティアイテムを詳細に複製/コピーしようとしています。 Itemにはパラメータもあり、これも複製する必要があります。ただし、ItemTypeは既存のItemTypeへの参照として残す必要があります。イラスト用Entity Framework 6動的な深さを持つエンティティのディープコピー/クローン

図:

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この試みの一定の深さレベルの場合:StackOverflowのの助けを借りて enter image description here

は(Entity Framework 5 deep copy/clone of an entityは)私は、次のかなりお粗末な試みが出ています魅力のように働く。しかし、あなたが見るように、これはそれぞれのより深いレベルではうまくいきません。このデザインでは、無制限のネストが可能です(ただし、私の考えでは5レベル以上は許されません)。

最大深度に応じて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; } 
} 

答えて

2

私はこの問題のより一般的なアプローチを発見しました。同様の問題が発生する場合があります誰のため は、ここで私は今のためにそれを解決する方法である:

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割り当ての前になければならないことに注意してください。 Othwerwiseでは、再帰は2番目のレベルで停止します。 さらに、再帰的メソッドは、Attached状態のエンティティで呼び出される必要があります。それ以外の場合、再帰は第2レベルでも停止します。

エンティティツリーが非常に深い場合は、反復アプローチを使用して再帰的なアプローチに置き換えることを検討してください。詳細については、をご覧ください:Wikipedia Recursion versus iteration

フィードバックと改善を歓迎します!

関連する問題