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

116

Obejrzałem tylko kilka webcastów, zanim zacząłem projektować kilka aplikacji Entity Framework. Naprawdę nie przeczytałem zbyt wiele dokumentacji i czuję, że teraz cierpię z tego powodu.

Używam List<T>na moich zajęciach i działa świetnie.

Teraz przeczytałem dokumentację i stwierdza, że ​​powinienem był użyć ICollection<T>. Zmieniłem się na to i nie spowodowało to nawet zmiany kontekstu modelu. Czy to dlatego, że zarówno List<T>i ICollection<T>dziedziczą IEnumerable<T>, i to jest faktycznie wymagane dla EF?

Jeśli jednak tak jest, dlaczego dokumentacja EF nie stwierdza, że IEnumerable<T>zamiast tego wymaga ICollection<T>?

W każdym razie, czy są jakieś wady tego, co zrobiłem, czy powinienem to zmienić?

wil
źródło

Odpowiedzi:

114

Entity Framework będzie używać, ICollection<T>ponieważ musi obsługiwać Addoperacje, które nie są częścią IEnumerable<T>interfejsu.

Należy również pamiętać, że były za pomocą ICollection<T>, to były tylko narażając go jako List<T>realizacji. List<T>przynosi wraz z nim IList<T>, ICollection<T>i IEnumerable<T>.

Jeśli chodzi o twoją zmianę, ekspozycja przez interfejs jest dobrym wyborem, mimo że List<T>działa. Interfejs definiuje kontrakt, ale nie implementację. Implementacja może się zmienić. W niektórych przypadkach może to być implementacjaHashSet<T> na przykład . (Nawiasem mówiąc, jest to sposób myślenia, którego możesz użyć nie tylko do Entity Framework. Dobrą praktyką zorientowaną obiektowo jest programowanie w kierunku interfejsu, a nie implementacji. Implementacje mogą się zmieniać i będą się zmieniać).

Anthony Pegram
źródło
2
Więc ... tylko dla mnie, aby zrozumieć nieco dalej - List dziedziczy IList, który dziedziczy ICollection, który dziedziczy IEnumerable?
wil
3
Tak, to jest łańcuch. List<T>musi realizacji każdego z tych interfejsów ( IList<T>, ICollection<T>, IEnumerable<T>), ponieważ hierarchii spadkowego. Na zakończenie, IList<T>podnosi również w górę nierodzajową IList, ICollectioni IEnumerableinterfejsów.
Anthony Pegram
Dziękuję ... Niektóre funkcje Ixxx wciąż wymykają się mi z zrozumienia! Miałeś jednak sens, ostatnia rzecz, która mnie denerwuje, jeśli IEnumerable dziedziczy po drugim Ixx, w jaki sposób dodaje się to do IEnumerable, jeśli Ienumerable jest tylko do odczytu? ... Jeśli jest to zbyt skomplikowane, nie martw się, gdy będę miał trochę czasu, spróbuję odpalić reflektor!
wil
10
Normalne operacje Linq nie dodają ani nie mutują rzeczy, po prostu filtrują, grupują, projektują itp. Sekwencje tylko do przodu, tylko do odczytu są wszystkim, co jest konieczne do obsługi tych operacji. Jeśli masz dostawcę Linq, takiego jak Entity Framework, który zajmuje się trwałością danych, możliwość dodawania jest istotną korzyścią, która wymaga mocniejszego interfejsu, który zaprasza ICollection<T>na imprezę (a ten interfejs niesie ze sobą to IEnumerable<T>, więc „normalna „Operacje Linq są nadal aktualne).
Anthony Pegram
@AnthonyPegram: Myślę, że stwierdzenie, że wszystkie trzy interfejsy muszą być zaimplementowane, jest całkowicie błędne. Ponieważ IList <T> dziedziczy ICollection <T>, który dziedziczy IEnumerable <T>, wystarczy List <T> po prostu zaimplementować IList <T>.
CJ7
51

Wybrali interfejs, który zrobili, ponieważ zapewnia zrozumiałą abstrakcję dla magicznych zapytań wykonywanych przez Entity Framework podczas korzystania z Linq.

Oto różnica między interfejsami:

  • IEnumerable<T> jest tylko do odczytu
  • Możesz dodawać i usuwać elementy do pliku ICollection<T>
  • Możesz zrobić losowy dostęp (według indeksu) do pliku List<T>

Poza tym ICollectioni IEnumerabledobrze mapuj na operacje bazy danych, ponieważ zapytania i dodawanie / usuwanie jednostek to rzeczy, które możesz zrobić w bazie danych.

Losowy dostęp według indeksu również nie jest mapowany, ponieważ musiałbyś mieć istniejący wynik zapytania, aby wykonać iterację, albo każdy losowy dostęp ponownie przeszukiwałby bazę danych. Na co by odwzorowany indeks? Numer wiersza? Nie ma wielu zapytań dotyczących numerów wierszy, które chciałbyś wykonać, i nie jest to w ogóle przydatne przy tworzeniu większych zapytań. Więc po prostu tego nie popierają.

ICollection<T> jest obsługiwany i umożliwia zarówno przeszukiwanie, jak i zmianę danych, więc używaj go.

Powód, dla którego List<T>działa na początku, jest taki, że implementacja EF na końcu zwraca jedną. Ale to jest na końcu twojego łańcucha zapytań, a nie na początku. Dlatego tworzenie właściwości ICollection<T>sprawi, że będzie bardziej oczywiste, że EF tworzy kilka instrukcji SQL i zwraca tylko List<T>na końcu, zamiast wykonywać zapytania dla każdego używanego poziomu Linq.

Merlyn Morgan-Graham
źródło
8

ICollection różni się od IEnumerable tym, że w rzeczywistości można dodawać elementy do kolekcji, podczas gdy w przypadku IEnumerable nie można. Na przykład w swoich klasach POCO chcesz użyć ICollection, jeśli chcesz zezwolić na dodawanie kolekcji. Uczyń ICollection wirtualną, aby skorzystać również z leniwego ładowania.

Ralph Lavelle
źródło
1
Chcę zrozumieć - możesz wykonać te same operacje (i więcej!) Z List <T>. Dlaczego ICollection <T>? Dlaczego nie wymienić <T>? Wygląda na prostsze i mocniejsze.
monstro
List <T> Implementuje ICollection i IEnumerable. Więcej operacji, ale wiąże się to z większym obciążeniem.
IronAces
4

Chociaż pytanie zostało opublikowane wiele lat temu, nadal jest aktualne, gdy ktoś szuka tego samego scenariusza.

Niedawno opublikowano [2015] artykuł w CodeProject, który szczegółowo wyjaśnia różnicę i przedstawia ją w formie graficznej z przykładowym kodem . Nie koncentruje się bezpośrednio na EF, ale nadal mam nadzieję, że będzie bardziej pomocny:

List vs IEnumerable vs IQueryable vs ICollection vs IDictionary

BiLaL
źródło