EntityFramework подсчет результатов запроса в сравнении со списком подсчета
Должен efQuery.ToList().Count
а также efQuery.Count()
производить ту же стоимость?
Как это возможно, что efQuery.ToList().Count
а также efQuery.Count()
не производить ту же стоимость?
//GetQuery() returns a default IDbSet which is used in EntityFramework
using (var ds = _provider.DataSource())
{
//return GetQuery(ds, filters).Count(); //returns 0???
return GetQuery(ds, filters).ToList().Count; //returns 605 which is correct based on filters
}
2 ответа
Просто столкнулся с этим сам. В моем случае проблема заключается в том, что в запросе есть предложение.Select(), которое заставляет устанавливать дальнейшие отношения, которые в конечном итоге фильтруют запрос дальше, поскольку внутреннее соединение отношений ограничивает результат.
Похоже, что.Count() не обрабатывает часть запроса.Select().
Так что я:
// projection created
var ordersData = orders.Select( ord => new OrderData() {
OrderId = ord.OrderId,
... more simple 1 - 1 order maps
// Related values that cause relations in SQL
TotalItemsCost = ord.OrderLines.Sum(lin => lin.Qty*lin.Price),
CustomerName = ord.Customer.Name,
};
var count = ordersData.Count(); // 207
var count = ordersData.ToList().Count // 192
Когда я сравниваю операторы SQL, я нахожу, что Count () выполняет очень простую сумму в таблице Orders, которая возвращает все заказы, в то время как второй запрос представляет собой монстр из 100+ строк SQL, который имеет 10 внутренних объединений, которые инициируются. Предложение Select () (получено несколько связанных значений / агрегатов, чем показано здесь).
По сути, это указывает на то, что.Count() не учитывает предложение.Select() при подсчете, поэтому те же отношения, которые вызывают дальнейшее ограничение результирующего набора, не запускаются для.Count().
Я смог сделать эту работу, явно добавив выражения к методу.Count(), которые извлекают некоторые из этих агрегированных значений результатов, которые также эффективно вводят их в запрос.Count():
var count = ordersData.Count( o=> o.TotalItemsCost != -999 &&
o.Customer.Name != "!@#"); // 207
Ключ заключается в том, чтобы убедиться, что любое из полей, которые вычисляются или извлекают связанные данные и вызывают срабатывание отношения, включены в выражение, которое заставляет Count () включить требуемые отношения в свой запрос.
Я понимаю, что это полный взлом, и я надеюсь, что есть лучший способ, но на данный момент это позволило нам, по крайней мере, получить правильное значение, не используя сначала массивные данные с помощью.ToList().
Предполагая, что здесь efQuery
является IQueryable
:
ToList()
на самом деле выполняет запрос. Если изменения в данных в хранилище данных, между вызовами ToList()
а также .Count()
, приведите к другому набору результатов, вызывая ToList()
пополнит список. ToList().Count
а также .Count()
должен соответствовать, пока данные в хранилище не изменят набор результатов снова.