我在实体框架中有一个非常简单的多对多表格,将我的批准连接到我的交易(如下所示)。
我正在尝试在审批对象内部进行查询,以计算审批中的交易金额,这应该相对容易。
如果我这样做,那么它的工作速度非常快。
int count;
EntitiesContainer dbContext = new EntitiesContainer ();
var aCnt = from a in dbContext.Approvals
where a.id == id
select a.Transactions.Count;
count = aCnt.First();
但是当我这样做时
count = Transactions.Count;
或者
count = Transactions.AsQueryable<Transaction>().Count();
它非常慢。我已经跟踪了在服务器上运行的sql,它确实似乎试图加载所有事务而不是仅仅对事务集合执行COUNT查询。
任何人都可以向我解释原因吗?
附加: 以下是EF模型对这两个类的看法
更新:
感谢所有回复,我相信我出错的地方是相信附加到Approval对象的集合将以IQueryable的形式执行。我将不得不对dbContext对象执行计数。
谢谢大家。
答案 0 :(得分:5)
var aCnt = from a in dbContext.Approvals
where a.id == id
select a.Transactions.Count;
EF自行编译查询,上述查询将编译为select count
个事务
与
不同count = Transactions.AsQueryable<Transaction>().Count();
count = Transactions.Count;
这些将从事务中选择所有记录,然后计算计数
答案 1 :(得分:1)
您的第一种方法允许在数据库服务器级别进行计数。它会要求数据库不返回记录,而是返回找到的记录数量。这是最有效的方法。
这并不是说其他方法可以有效地工作,但是对于其他两行,您首先要说明的是您从Approvals上的联接中检索事务。相反,在另外两行中,您只需单独使用Transactions集合并对其进行计数,基本上强制集合被填充以便对其进行计数。
答案 2 :(得分:1)
当您访问a.Transactions
属性时,则会加载事务列表(延迟加载)。如果您只想获得Count
,请使用以下内容:
dbContext.Transactions.Where(t => t.Approvals.Any(ap => ap.Id == a.Id)).Count();
其中a
获得批准。
答案 3 :(得分:1)
您的第一个代码段会导致在数据库服务器上执行查询。这是因为IQueryable
实例是由实体框架提供的ObjectQuery
类型,它执行必要的SQL转换然后执行。
第二个代码段说明如何使用IEnumerable
个实例。在最坏的情况下,Count()
通过枚举整个集合来处理它们。
在第三个代码段中,您尝试再次IEnumerable
IQueryable
。但是Enumerable.AsQueryable
方法无法知道它正在IEnumerable
得到了什么&#34;来了#34;来自实体框架。它能做的最好的事情是将IEnumerable
包装在EnumerableQuery
实例中,该实例只是动态编译给所有LINQ查询运算符的表达式树,并在内存中执行它们。
如果您需要由数据库服务器计算计数,您可以手动制定必需的查询(即,在代码段中编写已经执行的操作),或使用您可用的方法CreateSourceQuery
如果你不使用Code First。请注意,它确实会在数据库服务器上执行,因此如果您修改了集合并且尚未保存更改,则结果将与通过直接调用Count
返回的结果不同。