我们正在实施一些EF数据存储库,我们有一些查询包括TOP 1
我看过很多建议使用.Take(1)
的帖子
我正在审核的代码使用.First()
据我所知,这两个对象分配都会产生相同的结果,但它们是否真的解析为同一个查询?查询数据库时,两个请求实际上是TOP 1
吗?或者他们会将查询完整地执行到可枚举中,然后只需获取集合中的第一个条目吗?
此外,如果我们使用.FirstOrDefault()
那么为什么我们应该期待任何不同的行为呢?我知道当使用IEnumerable时,在空集合上调用.First()
会抛出,但如果 实际上只是将查询更改为包含TOP 1
那么我应该绝对不会.First()
和.FirstOrDefault()
之间的功能差异......对吗?
或者,是否有一些比这些Enumerable扩展更好的方法来使查询执行TOP 1
?
答案 0 :(得分:63)
来自LINQPad:
<强> C#强>:
age_Centers.Select(c => c.Id).First();
age_Centers.Select(c => c.Id).FirstOrDefault();
age_Centers.Select(c => c.Id).Take(1).Dump();
<强> SQL 强>:
SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO
SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO
SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
*请注意,Take(1)
枚举并返回IQueryable
。
答案 1 :(得分:5)
将DataContext Log属性重定向到文本文件的Console.Out,并查看每个选项产生的查询。
答案 2 :(得分:2)
**First()** operates on a collection of any number of objects and returns the first object. **Take(1)** operates on a collection of any number of objects and returns a collection containing the first object.
您也可以使用Single Single()对一个对象的集合进行操作,只返回该对象。
答案 3 :(得分:1)
.First()
如何运作:
如果集合是IList类型,则第一个元素由索引位置访问,该位置根据集合实现而不同。否则,迭代器返回第一个元素。
.Take(int count)
总是迭代。
如果有任何增益,如果集合实现IList
并且通过索引访问第一个元素的速度高于返回迭代器的速度,则会发生这种情况。我不相信这会很重要。 ;)
来源:
答案 4 :(得分:1)
首先会查询Take 1,因此查询没有区别。调用FirstOrDefault将是一步声明,因为Take返回IEnumerable,你还需要调用First。
首先会抛出异常,因此始终首选FirstOrDefault。
当然,编写EF查询转换器的人非常聪明,可以调用Take 1而不是执行整个结果集并返回第一项。
您可以使用SQL事件探查器进行验证。