ICollection <T> Vs List <T> in Entity Framework


114

Ho guardato solo alcuni webcast prima di iniziare a progettare alcune applicazioni Entity Framework. Non ho letto molta documentazione e ora mi sento come se ne soffrissi.

L'ho usato List<T>nelle mie classi e ha funzionato benissimo.

Ora ho letto della documentazione e si afferma che avrei dovuto usare ICollection<T>. Sono passato a questo e non ha nemmeno causato un cambiamento di contesto del modello. E 'questo perché entrambi List<T>ed ICollection<T>ereditano IEnumerable<T>, e questo è ciò che è effettivamente necessaria per EF?

Tuttavia, se questo è il caso, perché la documentazione EF non afferma che richiede IEnumerable<T>invece di ICollection<T>?

In ogni caso, ci sono degli svantaggi in quello che ho fatto o devo cambiarlo?

Risposte:


113

Entity Framework userebbe ICollection<T>perché deve supportare le Addoperazioni, che non fanno parte IEnumerable<T>dell'interfaccia.

Si noti inoltre che si stava utilizzando ICollection<T>, si erano semplicemente esponendola come l' List<T>implementazione. List<T>porta con sé IList<T>, ICollection<T>e IEnumerable<T>.

Per quanto riguarda la tua modifica, l'esposizione tramite l'interfaccia è una buona scelta, nonostante List<T>funzioni. L'interfaccia definisce il contratto ma non l'implementazione. L'implementazione potrebbe cambiare. In alcuni casi, forse l'implementazione potrebbe essere HashSet<T>, ad esempio. (Questa è una mentalità che potresti usare per qualcosa di più del semplice Entity Framework, tra l'altro. Una buona pratica orientata agli oggetti è programmare verso l'interfaccia e non l'implementazione. Le implementazioni possono cambiare e cambieranno).


2
Quindi ... solo per me per capire un po 'di più: List eredita IList, che eredita ICollection, che eredita IEnumerable?
wil

3
Sì, questa è la catena. List<T>deve attuare ciascuna di tali interfacce ( IList<T>, ICollection<T>, IEnumerable<T>) a causa della gerarchia di ereditarietà. Per il completamento, IList<T>raccoglie anche i non generici IList, ICollectione IEnumerableinterfacce.
Anthony Pegram

Grazie ... Alcune delle funzionalità di Ixxx ancora sfuggono alla mia comprensione! Hai comunque avuto senso un'ultima cosa che mi infastidisce, se l'altro Ixx eredita IEnumerable, come si aggiunge a IEnumerable se un Ienumerable è di sola lettura? ... Se è troppo complesso, non preoccuparti, quando avrò un po 'di tempo proverò ad accendere il riflettore!
wil

10
Le normali operazioni di Linq non aggiungono o modificano le cose, semplicemente filtrano, raggruppano, proiettano, ecc. Quando hai un provider Linq come Entity Framework che si occupa della persistenza dei dati, la capacità di aggiungere è un vantaggio sostanziale che richiede un'interfaccia più robusta, che è ciò che invita ICollection<T>alla festa (e questa interfaccia porta con sé IEnumerable<T>, quindi il "normale "Le operazioni di Linq sono ancora valide).
Anthony Pegram

@AnthonyPegram: Penso che sia assolutamente errato dire che tutte e tre le interfacce devono essere implementate. Poiché IList <T> eredita ICollection <T> che eredita IEnumerable <T>, è sufficiente che List <T> implementi semplicemente IList <T>.
CJ7

51

Hanno scelto l'interfaccia che hanno fatto perché fornisce un'astrazione comprensibile sulle query magiche che Entity Framework esegue quando si utilizza Linq.

Ecco la differenza tra le interfacce:

  • IEnumerable<T> è di sola lettura
  • Puoi aggiungere e rimuovere elementi in un file ICollection<T>
  • Puoi eseguire l'accesso casuale (tramite indice) a un file List<T>

Di questi, ICollectione IEnumerablemappalo bene alle operazioni del database, poiché eseguire query e aggiungere / rimuovere entità sono cose che potresti fare in un DB.

Anche l'accesso casuale per indice non viene mappato, poiché dovresti avere un risultato di query esistente su cui eseguire l'iterazione, altrimenti ogni accesso casuale interrogherebbe nuovamente il database. Inoltre, su cosa sarebbe mappato l'indice? Numero di riga? Non ci sono molte query sui numeri di riga che vorresti fare e non è affatto utile per creare query più grandi. Quindi semplicemente non lo supportano.

ICollection<T> è supportato e ti consentirà sia di eseguire query che di modificare i dati, quindi usalo.

Il motivo per cui List<T>funziona è perché l'implementazione EF finisce per restituirne uno alla fine. Ma è alla fine della catena di query, non all'inizio. Quindi rendere le tue proprietà ICollection<T>renderà più ovvio che EF crea un mucchio di SQL e restituisce solo un List<T>alla fine, piuttosto che eseguire query per ogni livello di Linq che usi.


8

ICollection differisce da IEnumerable in quanto puoi effettivamente aggiungere elementi alla raccolta, mentre con IEnumerable non puoi. Quindi nelle tue classi POCO, ad esempio, vuoi usare ICollection se intendi consentire l'aggiunta alla raccolta. Rendi virtuale ICollection per beneficiare anche del caricamento lento.


1
Voglio capire: puoi fare le stesse operazioni (e anche di più!) Con List <T>. Perché ICollection <T>? Perché non List <T>? Sembra più semplice e più potente.
monstro

List <T> Implementa ICollection e IEnumerable. Più operazioni ma con ciò si ottengono più costi generali.
IronAces

4

Sebbene la domanda sia stata posta anni fa, è ancora valida quando qualcuno cerca lo stesso scenario.

C'è un recente articolo [2015] CodeProject che spiega la differenza in molti dettagli e rappresentazione grafica con codice di esempio . Non è focalizzato direttamente su EF ma spero comunque che possa essere di maggiore aiuto:

List vs IEnumerable vs IQueryable vs ICollection vs IDictionary

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.