2015-11-23 13 views
6

Próbuję głęboko sklonować/skopiować obiekt Obiekt zawierający elementy dziecięce tego samego typu. Przedmiot ma również parametry, które również powinny zostać sklonowane. Element ItemType należy jednak pozostawić jako odniesienie do istniejącego ItemType.Struktura obiektu 6 głęboka kopia/klon podmiotu o dynamicznej głębokości

Schemat ilustracji: enter image description here

Z pomocą Stackoverflow (Entity Framework 5 deep copy/clone of an entity) I mają pochodzić z poniższego raczej kiepska próba:

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

na ustaloną głębokość poziomie od 3 Ta próba działa jak marzenie. Jednak, jak widać, nie jest to całkiem niezłe z każdym głębszym poziomem. Konstrukcja pozwala na nieskończoną liczbę zagnieżdżeń (w moim kontekście jednak nie powinno być więcej niż 5 poziomów).

Czy istnieje możliwość dynamicznego dodawania opcji Includes do IQueryable w zależności od maksymalnej głębokości?

Jest to pozycja, jednostka sklonować:

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

Odpowiedz

2

znalazłem bardziej ogólne podejście do tego problemu. Dla każdego, kto może napotkać podobny problem, oto jak to rozwiązać go teraz:

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

Należy pamiętać, że wywołanie rekurencyjne musi być przed alokacji EntityState.Added. W przeciwnym razie rekursja zatrzyma się na drugim poziomie. Ponadto metoda rekursywna musi zostać wywołana z Entity w Attached State. W przeciwnym razie rekursja zatrzyma się również na drugim poziomie.

Rozważ zastąpienie rekurencji podejściem iteratywnym, jeśli drzewo encji jest bardzo głębokie. Aby uzyskać więcej informacji, należy spojrzeć na: Wikipedia Recursion versus iteration

Informacje zwrotne i poprawki są mile widziane!

Powiązane problemy