Свойства навигации читаются каждый раз, когда к ним обращаются?(EF4.1) - PullRequest
1 голос
/ 10 июня 2011

Я использую EF 4.1 с отложенной загрузкой POCO.

Некоторые примеры запросов, которые я выполняю:

var discountsCount = product.Discounts.Count();  
var currentDiscountsCount = product.Discounts.Count(d=>d.IsCurrent);  
var expiredDiscountsCount = product.Discounts.Count(d=>d.IsExpired);  

Что я хотел бы знать, так это мои запросыимеет смысл или имеет низкую производительность:

Я каждый раз обращаюсь к базе данных, или результаты будут получены из кэшированных данных в DbContext?

Можно ли получить доступ к свойствам навигации "изчеши "каждый раз, как указано выше, или я должен их кэшировать, а затем выполнять дополнительные запросы к ним, например:

var discounts = product.Discounts;  
var current = discounts.Count(d=>d.IsCurrent);  
var expired = discounts.Count(d=>d.Expired);  

Как насчет сложного случая, подобного приведенному ниже, выполняет ли он всю коллекцию и затемвыполнять локальные операции над ним или он создает специальный запрос SQL, что означает, что я не могу повторно использовать результаты, чтобы избежать повторного попадания в базу данных:

var chained = discounts.OrderBy(d=>d.CreationDate).Where(d=>d.CreationDate < DateTime.Now).Count();

Спасибо за совет!

РЕДАКТИРОВАТЬ на основе комментариев ниже

Поэтому, как только я вызову свойство навигации (которое является коллекцией), оно загрузит весь граф объекта.Но что, если я отфильтровал эту коллекцию, используя .Count(d=>d...) или Select(d=>d...) или Min(d=>d...) и т. Д. Загружается ли также весь график или только конечные данные?

Ответы [ 2 ]

4 голосов
/ 10 июня 2011

product.Discounts (или любая другая навигационная коллекция) - это не IQueryable, а только IEnumerable. Операции LINQ, которые вы выполняете на product.Discounts, никогда не будут выдавать запрос к базе данных - за исключением того, что в случае отложенной загрузки product.Discounts будет загружен один раз из базы данных в память. Он будет загружен полностью - независимо от того, какую операцию LINQ или фильтр вы выполняете.

Если вы хотите выполнять фильтры или любые запросы к коллекциям навигации без полной загрузки коллекции в память, вы не должны получать доступ к коллекции навигации, но должны создавать запрос через контекст, например, в вашем примере:

var chained = context.Entry(product).Collection(p => p.Discounts).Query()
                     .Where(d => d.CreationDate < DateTime.Now).Count();

Это не приведет к загрузке Discounts коллекции product в память, но выполнит запрос в базе данных, а затем вернет одно число в качестве результата. Следующий запрос такого рода снова попадет в базу данных.

3 голосов
/ 10 июня 2011

В приведенных выше примерах коллекция скидок должна быть заполнена Ef при первом обращении к ней. Последующие запросы linq к коллекции Discount должны выполняться в памяти. Это будет даже включать последнее сложное выражение.

Вы также можете использовать метод «Включить», чтобы убедиться, что вы возвращаете связанную коллекцию в первый раз. пример .Include ("Скидки");

Если вы беспокоитесь о производительности, я бы порекомендовал использовать SQL Profiler, чтобы посмотреть, какой SQL выполняется.

...