Я хотел бы уточнить некоторые вещи из-за, казалось бы, противоречивых ответов (в основном из-за IEnumerable).
(1) IQueryable
расширяет интерфейс IEnumerable
. (Вы можете отправить IQueryable
на то, что ожидает IEnumerable
без ошибок.)
(2) И IQueryable
, и IEnumerable
LINQ пытаются выполнить отложенную загрузку при итерации по набору результатов. (Обратите внимание, что реализацию можно увидеть в методах расширения интерфейса для каждого типа.)
Другими словами, IEnumerables
не являются исключительно "в памяти". IQueryables
не всегда выполняются в базе данных. IEnumerable
должен загружать вещи в память (после извлечения, возможно, лениво), потому что у него нет поставщика абстрактных данных. IQueryables
полагается на абстрактный поставщик (например, LINQ-to-SQL), хотя это также может быть поставщик .NET в памяти.
Пример использования
(a) Получить список записей как IQueryable
из контекста EF. (Нет записей в памяти.)
(b) Передайте IQueryable
представлению, модель которого IEnumerable
. (Действителен. IQueryable
расширяется IEnumerable
.)
(c) Выполните итерацию и получите доступ к записям набора данных, дочерним объектам и свойствам из представления. (Может вызвать исключения!)
Возможные проблемы
(1) IEnumerable
пытается выполнить отложенную загрузку, и ваш контекст данных устарел. Исключение вызвано тем, что провайдер больше не доступен.
(2) Прокси-объекты сущностей Entity Framework включены (по умолчанию), и вы пытаетесь получить доступ к связанному (виртуальному) объекту с контекстом данных с истекшим сроком действия. То же, что (1).
(3) Несколько активных наборов результатов (MARS). Если вы выполняете итерацию по IEnumerable
в блоке foreach( var record in resultSet )
и одновременно пытаетесь получить доступ к record.childEntity.childProperty
, вы можете получить MARS из-за отложенной загрузки набора данных и реляционной сущности. Это вызовет исключение, если оно не включено в строке подключения.
Решение
- Я обнаружил, что включение MARS в строке подключения работает ненадежно. Я предлагаю вам избегать MARS, если это не является понятным и явно желательным.
Выполните запрос и сохраните результаты, вызвав resultList = resultSet.ToList()
Похоже, это самый простой способ убедиться, что ваши объекты находятся в памяти.
В случаях, когда вы обращаетесь к связанным сущностям, вам все равно может потребоваться контекст данных. Либо так, либо вы можете отключить прокси сущностей и явно Include
связанные сущности из вашего DbSet
.