2014-07-18 15 views
10
struttura

EsempioEntity Framework oggetto duplicato e tutte le proprietà secondarie

public class Page 
{ 
    public int PageId { get; set; } 
    public string Prop1 { get; set; } 
    public string Prop2 { get; set; } 
    public virtual List<Section> Sections { get; set; } 
} 

public class Section 
{ 
    public int SectionId { get; set; } 
    public int PageId { get; set; } 
    public virtual Page Page { get; set; } 
    public virtual List<Heading> Headings { get; set; } 
} 

public class Heading 
{ 
    public int HeadingId { get; set; } 
    public int SectionId { get; set; } 
    public virtual Section Section { get; set; } 
} 

Vale la pena notare che il mio attuale struttura ha più livelli di questo, ma questo dovrebbe essere sufficiente a spiegare quello che sto cercando di realizzare.

Così ho caricare il mio Page oggetto che poi clonare l'oggetto e fare alcune piccole modifiche alle proprietà di Page cioè Prop1, Prop2

Page pageFromDb = getPageMethod(); 
Page clonedPage = pageFromDb.Clone(); 
clonedPage.Prop1 = clonedPage.Prop1 + " Cloned"; 
addPageMethod(clonedPage); //Adds the page to db 

Nell'esempio di cui sopra clonedPage struttura va bene e viene aggiunto un nuovo Page al database. Tuttavia, credo perché gli ID degli oggetti figlio sono impostati e il rapporto tra i bambini è sempre uno a molti. L'oggetto originale pageFromDb perderà tutto il figlio come framework di entità anziché creare nuovi oggetti Section per il clonato Page aggiornerà lo Section.PageId alla pagina appena inserita.

Credo che una correzione per questo sarebbe quello di foreach, foreach, ecc e impostare tutti i Id di per 0 prima di inserire poi Entity Framework creerà nuovi record oggetto foreach. C'è un modo più semplice/migliore per clonare un oggetto in un ambiente framework entità.?

+2

Che cosa fa il metodo Clone? Sta facendo una copia profonda? Puoi dirgli di non copiare i campi di identificazione? Finché le raccolte sono corrette, EF creerà gli ID per te dopo gli inserimenti. – Tim

+0

@Tim Semplicemente usando AutoMapper in alto 'Pagina' livello oggetto. –

+0

possibile duplicato di [Clonazione dati su Entity Framework] (http://stackoverflow.com/questions/2185155/cloning-data-on-entity-framework) –

risposta

20

Affinché Entity Framework tratti il ​​clone come un intero nuovo oggetto grafico quando si mantiene il grafico, tutte le entità nel grafico devono essere disconnesso dal contesto in cui è stata richiamata l'entità radice.

Questo può essere fatto utilizzando il metodo AsNoTracking nel contesto.

Ad esempio, questo estrarrà una pagina e il relativo grafico delle sezioni dal database e disabiliterà il tracciamento. In pratica si tratta di un clone come se si aggiungesse questo al proprio Page DbSet e il salvataggio creerebbe un nuovo oggetto grafico nel database. Cioè una nuova entità di pagina e nuove entità di sezione di conseguenza. Nota, non avrai bisogno di chiamare il tuo metodo Clone.

var clone = context.Pages 
    .AsNoTracking() 
    .Including(pages => pages.Sections) 
    .Single(...); 
context.Pages.Add(clone); 
context.SaveChanges(); // creates an entirely new object graph in the database 
+0

'Ulteriori informazioni: Modifiche in conflitto al ruolo 'Section_Page_Target' della relazione 'Context.Section_Page' è stato rilevato. Suggerirei che anche se le modifiche non vengono monitorate, le proprietà di navigazione sono ancora popolate. –

+0

Hmmm è strano perché il clone della pagina (AsNoTracking) è completamente rimosso dal contesto e quindi non può entrare in conflitto ... Stai caricando la pagina originale con una singola chiamata al tuo contesto come sopra? Qualche altro lavoro in corso sul tuo contesto diverso dal caricamento della pagina e dal salvataggio del clone? –

+0

Ha funzionato alla grande! Grazie... –

1

Prova questo!

public Page CopyPage(int pageID) 
{ 
    using(Context context = new Context()) 
    { 
     context.Configuration.LazyLoadingEnabled = false; 
     Page dbPage = context.Pages.Where(p => p.PageId == pageID).Include(s => s.Sections.Select(s => s.Section)).First(); 
     Page page = dbPage.Clone(); 
     page.PageId = 0; 

     for (int i = 0; i < dbPage .Sections.Count; i++) 
      page.Sections[i] = new Section 
      { 
       SectionId = 0, 
       PageId = 0, 
       Page = null, 
       Headings = dbPage[i].Headings 
      }; 
     return page; 
    } 
} 

public Page Clone() 
    { 
     Object page = this.GetType().InvokeMember("", BindingFlags.CreateInstance, null, this, null); 

     foreach(PropertyInfo propertyInfo in this.GetType().GetProperties()) 
     { 
      if(propertyInfo.CanWrite) 
      { 
       propertyInfo.SetValue(page, propertyInfo.GetValue(this, null), null); 
      } 
     } 

     return page; 
    } 
Problemi correlati