ICollection <T> против List <T> в Entity Framework

116

Я просмотрел всего несколько веб-трансляций, прежде чем приступил к разработке нескольких приложений Entity Framework. Я действительно не читал так много документации и чувствую, что сейчас страдаю из-за этого.

Я использовал List<T>на своих занятиях, и это отлично сработало.

Теперь я прочитал некоторую документацию, и в ней говорится, что я должен был использовать ICollection<T>. Я перешел на это, и это даже не привело к изменению контекста модели. Это потому, что оба List<T>и ICollection<T>наследуют IEnumerable<T>, а это то, что на самом деле требуется для EF?

Однако, если это так, почему в документации EF не указано, что IEnumerable<T>вместо ICollection<T>?

В любом случае, есть ли недостатки в том, что я сделал, или мне стоит это изменить?

Виль
источник

Ответы:

114

Entity Framework будет использовать, ICollection<T>потому что он должен поддерживать Addоперации, которые не являются частью IEnumerable<T>интерфейса.

Также обратите внимание , что вы были с помощью ICollection<T>, вы просто выставляя его в качестве List<T>реализации. List<T>приносит вместе с ним IList<T>, ICollection<T>и IEnumerable<T>.

Что касается вашего изменения, то показ через интерфейс - хороший выбор, несмотря на то, что он List<T>работает. Интерфейс определяет контракт, но не реализацию. Реализация могла измениться. В некоторых случаях, возможно, реализацией может быть HashSet<T>, например. (Кстати, это образ мышления, который можно использовать не только для Entity Framework. Хорошей объектно-ориентированной практикой является программирование в направлении интерфейса, а не реализации. Реализации могут и будут меняться.)

Энтони Пеграм
источник
2
Итак ... просто для меня, чтобы понять немного дальше - List наследует IList, который наследует ICollection, который наследует IEnumerable?
Wil
3
Да, это цепочка. List<T>должен осуществить каждый из этих интерфейсов ( IList<T>, ICollection<T>, IEnumerable<T>) из - за иерархии наследования. Для завершения, IList<T>также поднимает необщие IList, ICollectionи IEnumerableинтерфейсы.
Энтони Пеграм
Спасибо ... Некоторые особенности Ixxx до сих пор ускользают от моего понимания! Вы поняли, однако, еще одно, что меня раздражает: если другие Ixx наследуют IEnumerable, как они добавляются к IEnumerable, если Ienumerable доступен только для чтения? ... Если будет слишком сложно, не волнуйтесь, когда будет немного времени, я попробую зажечь рефлектор!
Wil
10
Обычные операции Linq не добавляют и не изменяют объекты, они просто фильтруют, группируют, проектируют и т. Д. Последовательности только для прямого чтения и только для чтения - это все, что необходимо для поддержки этих операций. Когда у вас есть поставщик Linq, такой как Entity Framework, который имеет дело с сохранением данных, возможность добавления является существенным преимуществом, требующим более мощного интерфейса, что и приглашает ICollection<T>участников (и этот интерфейс приносит с собой IEnumerable<T>, так что "нормальный «Операции Linq все еще действительны).
Энтони Пеграм
@AnthonyPegram: Я считаю, что категорически неверно говорить, что все три интерфейса должны быть реализованы. Поскольку IList <T> наследует ICollection <T>, который наследует IEnumerable <T>, для List <T> достаточно просто реализовать IList <T>.
CJ7
51

Они выбрали интерфейс, который они сделали, потому что он дает понятную абстракцию над волшебными запросами, которые Entity Framework выполняет, когда вы используете Linq.

Вот разница между интерфейсами:

  • IEnumerable<T> только для чтения
  • Вы можете добавлять и удалять элементы в ICollection<T>
  • Вы можете выполнять произвольный доступ (по индексу) к List<T>

Из них ICollectionи IEnumerableхорошо сопоставляются с операциями с базой данных, поскольку запросы и добавление / удаление объектов - это то, что вы можете делать в БД.

Произвольный доступ по индексу также не отображается, так как вам нужно будет иметь существующий результат запроса для итерации, иначе каждый случайный доступ будет запрашивать базу данных снова. Кроме того, на что будет отображаться индекс? Номер строки? Не так много запросов с номерами строк, которые вы хотели бы выполнять, и это совершенно бесполезно при построении более крупных запросов. Так что они просто не поддерживают это.

ICollection<T> поддерживается и позволит вам как запрашивать, так и изменять данные, поэтому используйте его.

Причина, по которой List<T>работает с самого начала, заключается в том, что реализация EF в конечном итоге возвращает единицу. Но это в конце цепочки запросов, а не в начале. Таким образом, создание ваших свойств ICollection<T>сделает более очевидным, что EF создает связку SQL и возвращает только List<T>в конце, а не выполняет запросы для каждого уровня Linq, который вы используете.

Мерлин Морган-Грэм
источник
8

ICollection отличается от IEnumerable тем, что вы действительно можете добавлять элементы в коллекцию, тогда как с IEnumerable вы не можете. Итак, в ваших классах POCO, например, вы хотите использовать ICollection, если вы намереваетесь разрешить добавление коллекции в. Сделайте ICollection виртуальным, чтобы получить выгоду от отложенной загрузки.

Ральф Лавель
источник
1
Я хочу понять - вы можете делать те же операции (и даже больше!) С List <T>. Почему ICollection <T>? Почему не List <T>? Выглядит проще и мощнее.
monstro
List <T> Реализует ICollection и IEnumerable. Больше операций, но с этим больше накладных расходов.
IronAces
4

Хотя вопрос был опубликован много лет назад, он все еще актуален, когда кто-то ищет тот же сценарий.

Недавно вышла статья CodeProject [2015], в которой подробно объясняется разница в графическом представлении с примерами кода . Он не ориентирован непосредственно на EF, но все же надеюсь, что он будет более полезным:

Список против IEnumerable против IQueryable против ICollection против IDictionary

BiLaL
источник