Entity Framework - Запросы из ObjectContext против Запроса из свойства навигации
Я заметил, что в зависимости от того, как я извлекаю данные из моей модели Entity Framework, я получаю разные типы результатов. Например, при получении списка сотрудников в конкретном отделе:
Если я вытащить непосредственно из ObjectContext, я получу IQueryable<Employee>
что на самом деле System.Data.Objects.ObjectQuery<Employee>
:
var employees = MyObjectContext.Employees.Where(e => e.DepartmentId == MyDepartment.Id && e.SomeCondtition)
Но если я использую свойство навигации MyDepartment, я получаю IEnumerable<Employee>
что на самом деле System.Linq.WhereEnumerableIterator<Employee>
(закрытый класс в System.Linq.Enumerable):
var employees = MyDeparment.Employees.Where(e => e.SomeCondtition)
В следующем коде я интенсивно использую employees
в нескольких запросах LINQ (Where
, OrderBy
, First
, Sum
, так далее.)
Должен ли я учитывать, какой метод запроса я использую? Будет ли разница в производительности? Использует ли последний отложенное исполнение? Есть ли лучшая практика? Или это не имеет значения?
Я спрашиваю об этом, потому что после установки ReShaper 6 я получаю много возможных многократных перечислений предупреждений IEnumerable при использовании последнего метода, но ни одного при использовании прямых запросов. Я использую последний метод чаще, просто потому, что писать намного чище, и мне интересно, действительно ли это дало отрицательный эффект!
1 ответ
Здесь очень большая разница.
Если вы используете первый подход, у вас есть IQueryable
= дерево выражений, и вы все еще можете добавлять другие выражения, и только когда вы выполняете запрос (отложенное выполнение), дерево выражений будет преобразовано в SQL и выполнено в базе данных. Так что, если вы используете свой первый пример и добавляете .Sum
что-то, что вы действительно выполните операцию в базе данных, и он будет передавать только один номер обратно в ваше приложение. Это связь с сущностями.
Второй пример использует в коллекции памяти. Свойство навигации не представляет IQueryable
(дерево выражений). Все команды linq обрабатываются как linq-to-objects = все записи, представляющие связанные данные в свойстве навигации, должны быть сначала загружены из базы данных в ваше приложение, и все операции выполняются в памяти вашего сервера приложений. Вы можете загрузить свойство навигации с нетерпением (с помощью Include
), явно (используя Load
) или лениво (это выполняется автоматически при первом доступе к свойству, если включена отложенная загрузка). Поэтому, если вы хотите получить сумму чего-либо, этот сценарий требует загрузки всех данных из базы данных, а затем выполнения операции локально.