IEnumerable<T>.Count() 和 List<T>.Count 在 Entity Framework 中的区别

3

我正在使用Entity Framework检索项目列表,如果检索到某些项目,则对其执行某些操作。

var items = db.MyTable.Where(t => t.Expiration < DateTime.Now).ToList();
if(items.Count != 0)
{
    // Do something... 
}

if语句也可以写成以下形式:

if(items.Count() != 0)
{
    // Do something... 
}

在第一个案例中,.Count是一个List<T>.Count属性。在第二个案例中,.Count()IEnumerable<T>.Count()扩展方法。
虽然这两种方法都可以达到相同的结果,但是有没有一种更受欢迎呢?(可能在性能上有所不同?)

2
Enumerable.Count 的优点是您可以稍后更改序列的类型而不会破坏代码。但请注意,如果不是集合,则 Count() 枚举整个序列,而 Any 在第一个项目处停止,因此 Any 更可读且更好。 - Tim Schmelter
2
@lazyberezovsky:这是微观优化。除此之外,在一个返回所有记录的实体框架查询上使用Count()只是为了知道是否有一条记录,那真的很低效。另外,Any表明我想知道是否有一个项目,而不是有多少个项目。所以它也更易读。 - Tim Schmelter
@TimSchmelter:那么您是否建议使用 IQueryable<T>.Count() 来确定是否有任何记录。如果有,那么发出另一个查询并执行我上面所做的操作 (IQueryable<T>.ToList()) 来获取项目? - sakura-bloom
在这种情况下,他将向服务器发送两个查询,而没有任何警告。简单的“Count”会抱怨集合类型更改。我的先前评论并不是关于“Any()”的使用 - 而是关于在非常小的上下文中编写灵活的抽象代码。 - Sergey Berezovskiy
1
重要的是要明白,一旦你加入了 ToList,你就不再享受延迟查询的好处了。你现在不再使用 LINQ-to-Entities 提供程序,而是使用 LINQ-to-Objects。有许多重要的区别,例如 Count() 不再被翻译成 SQL,而是推迟到底层实现,字符串比较也不再是大小写不敏感的。 - tvanfosson
显示剩余7条评论
3个回答

9
Enumerable.Count<T>IEnumerable<T>的扩展方法)如果底层类型是ICollection<T>,则调用Count,因此对于List<T>没有区别。 Queryable.Count<T>IQueryable<T>的扩展方法)将使用底层查询提供程序,在许多情况下会将计数推送到实际的SQL中,这比在内存中计算对象要快得多。
如果应用了过滤器(例如Count(i => i.Name = "John"))或者底层类型不是ICollection<T>,则枚举集合以计算计数。

有一个更受欢迎的吗?

我通常更喜欢使用Count(),因为1)它更便携(底层类型可以是实现IEnumerable<T>IQueryable<T>的任何内容),2)如果需要,更容易添加筛选器。
正如Tim在他的评论中所述,我也更喜欢使用Any()而不是Count() > 0,因为它不必实际计算项数 - 它只会检查是否存在一个项目。相反,我使用!Any()而不是Count() == 0

2

这取决于底层集合以及Linq将从哪里获取数据。例如,如果是SQL,则使用.ToList()会导致查询返回整个列表,然后对其进行计数。然而,.Count()扩展方法将把它转换为数据库端的SQL COUNT语句。在这种情况下,性能差异就会显而易见。

对于标准的List或Collection,如D. Stanley的回答所述。


1
我认为这取决于 if 块内发生了什么。 如果您只是进行检查以确定是否对基础枚举执行一系列操作,则在任何情况下都可能不需要它。 只需遍历枚举(也省略 ToList)。 如果您没有在 if 块内使用集合,则应避免使用 ToList,并绝对使用 Any 而不是任何 Count/Count() 方法。
一旦您执行了 ToList,则不再使用 Entity Framework,我预计 Count() 仅比 Count 稍慢,因为如果底层集合是 ICollection<T>,它会推迟到该实现。 唯一的开销将是确定它是否实现了该接口。

http://msdn.microsoft.com/en-us/library/bb338038.aspx

备注: 如果源类型实现了ICollection<T>,则使用该实现获取元素的计数。否则,此方法确定计数。

你能详细说明一下 如果你只是在检查是否对基础枚举执行一系列操作,那么它可能根本不需要。 的意思吗? - sakura-bloom
1
如果你的检查只是 if (items.Any()) { foreach (var item in items) { .... } },那么你不需要先进行检查。如果集合中没有元素,foreach 循环同样可以正常工作。 - tvanfosson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接