8

应该efQuery.ToList().CountefQuery.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
}

4

2 回答 2

6

我自己也遇到了这个。在我的情况下,问题是查询有一个 .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 表执行了一个非常简单的 SUM,它返回所有订单,而第二个查询是 100 多行 SQL 的怪物,其中有 10 个由 . Select() 子句(检索到的相关值/聚合比此处显示的要多)。

基本上,这似乎表明 .Count() 在计算时没有考虑 .Select() 子句,因此不会为 .Count() 触发那些导致进一步约束结果集的相同关系。

我已经能够通过向 .Count() 方法显式添加表达式来完成这项工作,该方法将一些聚合结果值拉入,这些结果值也有效地强制它们进入 .Count() 查询:

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

关键是确保计算或提取相关数据并导致关系触发的任何字段都包含在强制 Count() 在其查询中包含所需关系的表达式中。

我意识到这是一个彻底的黑客攻击,我希望有更好的方法,但目前这至少使我们能够获得正确的价值,而无需首先使用 .ToList() 拉下大量数据。

于 2013-09-26T04:45:20.550 回答
1

Assuming here that efQuery is IQueryable:

ToList() actually executes a query. If changes to data in the datastore, between calls to ToList() and .Count(), result in a different resultset, calling ToList() will repopulate the list. ToList().Count and .Count() should then match until the data in the store changes the resultset again.

于 2013-07-03T15:29:24.063 回答