2010-01-13 13 views
25

Ho incontrato un problema interessante con Entity Framework e basato sul codice che ho dovuto usare per affrontarlo. Sospetto che la mia soluzione non sia l'ideale. Ho una relazione 1-a-molti tra la Tabella A e la Tabella B in cui le entità in TabellaB hanno un riferimento a TabellaA. Ho uno scenario in cui voglio cancellare contemporaneamente tutti i bambini di una riga in TableA e ho pensato che questo potrebbe essere raggiungere semplicemente deselezionando la collezione:Entity Framework - Clear a Child Collection

Entity.Children.Clear() 

Purtroppo, quando ho tentato di salvare le modifiche questo prodotto come straniera Violazione chiave.

viene aggiunta una relazione o cancellati da un AssociationSet 'FK_EntityB_EntityA'. Con i vincoli di cardinalità , è necessario aggiungere o eliminare una corrispondente "EntityB" .

La soluzione che ho trovato era quella di eliminare manualmente l'oggetto tramite DeleteObject() del contesto dell'entità, ma so solo che la logica che sto usando deve essere sbagliata.

while (collection.Any()) 
    Entities.DeleteObject(collection.First()); 

Per uno, il fatto che ho dovuto usare un ciclo in cui() sembra molto meno che ideale, ma suppongo che sia puramente una valutazione semantica da parte mia. In ogni caso, c'è qualcosa di sbagliato in come sto facendo questo, o c'è forse un modo migliore per cancellare una raccolta di entità figlio di un'entità tale che Entity Framework chiama correttamente un'eliminazione dell'archivio dati su tutti gli oggetti rimossi?

risposta

20

Clear() rimuove l'riferimento all'entità, non all'entità stessa.

Se si intende questo per essere sempre la stessa operazione, si potrebbe gestire AssociationChanged:

Entity.Children.AssociationChanged += 
    new CollectionChangeEventHandler(EntityChildrenChanged); 
Entity.Children.Clear();    

    private void EntityChildrenChanged(object sender, 
     CollectionChangeEventArgs e) 
    { 
     // Check for a related reference being removed. 
     if (e.Action == CollectionChangeAction.Remove) 
     { 
      Context.DeleteObject(e.Element); 
     } 
    } 

È possibile costruire questo al tuo soggetto utilizzando una classe parziale.

+0

Questo sembra perfetto. Da una classe parziale esiste una rotta diretta (o indiretta) al contesto? –

+1

sì, c'è una via indiretta: http: //blogs.msdn.com/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx –

+0

Sembra quasi che stia meglio semplicemente costruendo il ciclo while() cancellazione nel mio repository, quindi posso riutilizzarlo facilmente. Non dovrò preoccuparmi degli avvertimenti di risolvere il contesto ed è adeguatamente flessibile. Tuttavia, non ho dovuto scrivere un ciclo while() in C# per un po 'di tempo, mi sembra quasi sbagliato. –

5

È possibile creare una relazione di identificazione tra entità padre e figlio e EF eliminerà l'entità figlio quando la si elimina dalla raccolta del genitore.

public class Parent 
    { 
     public int ParentId {get;set;} 
     public ICollection<Child> Children {get;set;} 
    } 

    public class Child 
    {   
     public int ChildId {get;set;} 
     public int ParentId {get;set;} 
    } 

configurazione Mapping:

modelBuilder.Entity<Child>().HasKey(x => new { x.ChildId, x.ParentId }); 
    modelBuilder.Entity<Parent>().HasMany(x => x.Children).WithRequired().HasForeignKey(x => x.ParentId); 
5

Trucco: Quando si imposta il rapporto tra genitore e figlio, dovrete creare una chiave "composite" sul bambino. In questo modo, quando dici al genitore di eliminare 1 o tutti i suoi figli, i record correlati verranno effettivamente cancellati dal database.

Per configurare chiave composita utilizzando API Fluent:

modelBuilder.Entity<Child>().HasKey(t => new { t.ParentId, t.ChildId }); 

Poi, per eliminare i relativi figli:

var parent = _context.Parents.SingleOrDefault(p => p.ParentId == parentId); 

var childToRemove = parent.Children.First(); // Change the logic 
parent.Children.Remove(childToRemove); 

// you can delete all children if you want 
// parent.Children.Clear(); 

_context.SaveChanges(); 

Fatto!