2010-10-06 11 views
11

Qual è il modo corretto per eliminare tutti gli elementi di raccolta di un'entità EF? Nel seguente codice, DocumentItems è la raccolta di elementi di documento correlati per un documento. Questo codice procede su Clear() ma fallisce su SaveChanges() perché gli elementi correlati sono connessi al loro documento tramite FK e FK è obbligatorio. Quindi immagino che in qualche modo rimangano sospesi in aria senza una chiave esterna dopo Clear().Metodi EntityCollection Clear() e Remove()

Risolvo questo con un ciclo foreach sopra la raccolta chiamando Remove() su ciascun elemento o c'è un altro modo?

// remove existing document items to prepare for refreshing them 
existing.DocumentItems.Clear(); 
// adds new Document Items 
PrepareInvoice(existing, collection); 
_repository.SaveChanges(); 

risposta

9

Clear rimuove solo il riferimento, ma non elimina l'intero.

Nella tua situazione

existing.DocumentItems.Clear(); 

Tutti DocumentItems del EntitySet avranno eliminato ma si dovrà rimuovere/Eliminare il DocumentItem reale o il commit con fallire, proprio come si farebbe se si è tentato di eliminare nel database.

È necessario un ciclo tra staccare tutti i riferimenti, e quindi eliminare l'entità che si desidera rimuovere (a meno che la sua nullable e nella tua situazione non è)


In alternativa, ho visto le implementazioni che utilizzano chiaro e un AssociationChangedHandler per eliminare automaticamente il vecchio oggetto. Fondamentalmente se la modifica è "cancella/rimuovi" chiama DeleteObject() sull'oggetto orfano.

+5

Per prima cosa penso che sia ironico parlare di come "Clear" non è chiaro. La mia comprensione è che sono diversi. Clear dice solo rimuovere il puntatore (in memoria) di questi oggetti. 'Rimuovi' dice rimuovi dalla mia lista e segna per la cancellazione ... per favore correggimi se ho detto qualcosa di non valido. – Nix

0

Proprio per rispondere a Nix commento alla risposta,

mi sembra che il metodo EntityCollection.Remove solo marchi per l'eliminazione le relazioni e le entità, così come il metodo EntityCollection.Clear fa.

So che la documentazione dice che anche l'entità sarà contrassegnata per la cancellazione ma nel mio test ho il comportamento che ho descritto (qualcuno può spiegarmi perché?).

Quindi, se si dispone di uno o più vincoli di chiave esterna nel modello concettuale, non è possibile salvare le modifiche nel contesto nell'archivio di persistenza.

L'unico modo che ho trovato (dal momento che non voglio CascadeDelete) è il looping tra i bambini e invocare context.DeleteObject su ciascuno di essi, rimuovendo così l'entità e la relazione associata.

13

Questo è un modo per eliminare gli elementi nella raccolta.

VB

TEntityCollection.ToList().ForEach(Sub(o) ctx.DeleteObject(o)) 

C#

TEntityCollection.ToList().ForEach(x => ctx.DeleteObject(x)) 

allora avete bisogno di chiamare

ctx.SaveChanges() 
+0

Come è fatto in EF6? – vijayst

+0

Penso che EF 6 abbia un nuovo metodo chiamato RemoveRange che non ho effettivamente usato ma è un collegamento a qualcuno che ha:). http://stackoverflow.com/questions/21568479/how-can-i-delete-1-000-rows-with-ef6 –

+0

RemoveRange risolto. Grazie. – vijayst

1

Sì, un anno, ma su una nota minore ...dal momento che DeleteObject prende un parametro, che è lo stesso tipo come argomento per l'espressione lambda, si può semplicemente utilizzare:

entityCollection.ToList().ForEach(ctx.DeleteObject); 

Non sono sicuro se VB supporta una sintassi simile, però. Chiunque?

1

Trucco: quando si imposta la relazione tra Genitore e Figlio, è necessario creare un tasto "composito" 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); 

// or, you can delete all children 
// parent.Children.Clear(); 

_context.SaveChanges(); 

Fatto!