EntityFramework计数查询结果与计数列表

时间:2013-07-03 15:23:07

标签: entity-framework count deferred-execution

efQuery.ToList().CountefQuery.Count()应该生成相同的值吗?

efQuery.ToList().CountefQuery.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 个答案:

答案 0 :(得分: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语句时,我发现Count()在Orders表上执行一个非常简单的SUM,它返回所有订单,而第二个查询是100多行SQL的怪物,有10个内部联接被触发通过.Select()子句(检索到的更多相关值/聚合比此处所示)。

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

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

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

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

我意识到这是一个彻头彻尾的黑客,我希望有一个更好的方法,但目前这使得我们至少能够获得正确的价值,而不会先使用.ToList()大量数据。

答案 1 :(得分:1)

此处假设efQueryIQueryable

ToList()实际执行查询。如果对数据存储区中的数据进行更改(对ToList().Count()的调用)会导致结果集不同,则调用ToList()将重新填充列表。然后,ToList().Count.Count()应匹配,直到商店中的数据再次更改结果集。