2013-07-03 4 views
7

Должно ли efQuery.ToList().Count и efQuery.Count() произвести такое же значение? EntityFramework подсчет результатов запроса по сравнению с подсчетом

Как это возможно, что 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 
} 

+1

Является ли efQuery IEnumerable или IQueryable? Также, если бы вы могли опубликовать свой фактический код, который бы помог. – Maess

+0

efQuery - это 'IQueryable', это запрос, который еще не был выполнен против базы данных. Я добавил код. – ReFocus

ответ

1

Предполагая, что здесь efQuery является IQueryable:

ToList() фактически выполняет запрос. Если изменения данных в хранилище данных, между вызовами ToList() и .Count(), приведут к другому набору результатов, вызывающий ToList() будет переполнять список. ToList().Count и .Count() должны совпадать до тех пор, пока данные в магазине не изменят набор результатов еще раз.

+1

Данные не меняются между вызовами. Я могу воспроизвести эту проблему каждый раз, когда я запускаю код. Оба вызова дают разные результаты. Даже Resharper говорит мне, что я должен использовать метод '.Count()' вместо того, чтобы форматировать '.ToList()' и использовать свойство '.Count' ... – ReFocus

+1

Count() возвращает 0, потому что список еще не заполнен , Вы должны выполнить запрос с помощью ToList(), прежде чем запрос будет фактически выполнен. Если вы добавите a.Count() (без ToList()) после строки ToList(), счет будет правильным. –

+2

Нет, 'Count()' должен вызывать запрос на 'IQueryable' - http://stackoverflow.com/questions/890381/how-to-count-rows-withinentityframework-without-loading-contents – ReFocus

5

Просто наткнулся на это сам. В моем случае проблема заключается в том, что запрос имеет предложение .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 я считаю, что граф() делает очень простой SUM на столе заказов, который возвращает все заказы, в то время как второй запрос монстр 100 + строки SQL, которые имеют 10 внутренних объединений, которые инициируются предложением .Select() (есть еще несколько связанных значений/агрегаций, полученных, чем показано здесь).

В основном это указывает на то, что .Count() не принимает предложение .Select() во внимание при его подсчете, поэтому те же отношения, которые вызывают дальнейшее ограничение набора результатов, не запускаются для .Count().

я смог сделать эту работу явно добавляя выражения метода .Count(), которые тянут в некоторых из этих агрегированных значений результатов, которые эффективно принуждают их в .Count() запрос, а также:

var count = ordersData.Count(o=> o.TotalItemsCost != -999 && 
            o.Customer.Name != "[email protected]#"); // 207 

Ключ должен удостовериться, что любое из полей, которые вычислены или связаны с связанными данными и вызывают связь с огнем, включены в выражение, которое заставляет Count() включать в запрос необходимые отношения.

Я понимаю, что это полный хак, и я надеюсь, что есть лучший способ, но на данный момент это позволило нам хотя бы получить правильное значение, не сбрасывая массивные данные с помощью .ToList().

Смежные вопросы