实体框架COUNT正在对所有记录进行SELECT

时间:2014-06-09 12:56:07

标签: c# entity-framework

分析我的代码,因为它需要很长时间才能执行,它生成一个SELECT而不是COUNT,因为有20,000条记录,它非常慢。

这是代码:

var catViewModel= new CatViewModel();

var catContext = new CatEntities();

var catAccount = catContext.Account.Single(c => c.AccountId == accountId);

catViewModel.NumberOfCats = catAccount.Cats.Count();

这是直截了当的东西,但是探查器显示的代码是:

exec sp_executesql N'SELECT 
[Extent1].xxxxx AS yyyyy, 
[Extent1].xxxxx AS yyyyy, 
[Extent1].xxxxx AS yyyyy, 
[Extent1].xxxxx AS yyyyy // You get the idea
FROM [dbo].[Cats] AS [Extent1]
WHERE Cats.[AccountId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=7

我之前从未见过这种行为,有什么想法吗?

编辑:如果我只是这样做,它是固定的:

catViewModel.NumberOfRecords = catContext.Cats.Where(c => c.AccountId == accountId).Count();

我仍然想知道前者为什么不起作用。

2 个答案:

答案 0 :(得分:4)

所以你在这里有2个完全独立的查询,我想我可以解释为什么你会得到不同的结果。我们来看看第一个

// pull a single account record
var catAccount = catContext.Account.Single(c => c.AccountId == accountId);
// count all the associated Cat records against said account
catViewModel.NumberOfCats = catAccount.Cats.Count();

假设Cats0..*之间存在Account关系并假设您正在利用框架功能懒洋洋地加载外表,那么您首次调用catAccounts.Cats将为该特定帐户的所有关联SELECT记录生成Cat。这导致表被带入内存,因此对Count()的调用将导致对内存中集合的Count属性进行内部检查(因此不生成COUNT SQL。

第二个查询

catViewModel.NumberOfRecords = 
    catContext.Cats.Where(c => c.AccountId == accountId).Count();

直接针对Cats表(可能是IQueryable<T>),因此针对该表执行的唯一操作是Where / Count,这两个操作都将是在执行之前在DB端进行评估,因此它显然比第一个更有效。

但是,如果您同时需要AccountCats,那么我建议您急切地在抓取时加载数据,这样您就可以提前点击

var catAccount = catContext.Account.Include(a => a.Cats).Single(...);

答案 1 :(得分:2)

大多数情况下,当有人访问实体的子集合时,这是因为记录数量有限,填充集合是可以接受的。因此,当您访问:

catAccount.Cats

(无论你接下来做什么),填充该集合。然后,您的.Count()将在本地内存中集合上运行。问题是你不想要那个。现在您有两个选择:

  • 检查您的提供商是否提供某种机制来制作查询而不是集合
  • 动态构建查询
  • 改为访问核心数据模型

如果你这样做,我非常有信心:

catViewModel.NumberOfRecords =
    catContext.Cats.Count(c => c.AccountId == accountId);

它会正常工作。不太方便?当然。但是&#34;工作&#34;优于&#34;方便&#34;。