实体框架4 Single()vs First()vs FirstOrDefault()


119

我有一个恶魔般的时间来比较查询单个项目的不同方法以及何时使用每种方法的比较。

没有人有一个将所有这些都进行比较的链接,或者有一个简短的解释说明您为什么要在一个之上使用另一个?我还有更多未知的运营商吗?

谢谢。

Answers:


205

以下是不同方法的概述:

  • Find()-当您想通过主键获取项目时。如果找不到项目,它将返回null。它会在进入数据库之前先检查上下文(正如Yaron在评论中指出的),如果您需要在同一个上下文还活着的情况下多次获取相同的实体,这可能是一个重要的效率因素。

  • Single()-当您期望查询完全返回一个项目时。如果查询未完全返回一项,则将引发异常。

  • SingleOrDefault()-当您期望查询返回零或一项(即,不确定是否存在具有给定键的项)时。如果查询未返回零或一项,则将引发异常。

  • First()-当您希望查询返回一个或多个项目,但您只想访问代码中的第一个项目时(此处的查询顺序很重要)。如果查询未返回至少一项,则将引发异常。

  • FirstOrDefault()-当您期望查询返回零个或多个项目,但您只想访问代码中的第一个项目时(即,您不确定是否存在具有给定键的项目)


1
这取决于场景。如果您知道应该始终从数据库中获得一条记录,那么对于给定的查询,它不会多也不会少,那么Single()是使用的“正确”方法。在其他情况下,其他情况可能更合适。在早期版本的EF中,我们仅限于First()和FirstOrDefault(),它们适用于您希望获得单个记录的情况,但是如果您实际获得的收益超过单个记录,它们将不会警告您,这可能很重要,具体取决于情况。
史蒂夫·威尔考克

1
谢谢。我看不到自己需要First(),而Single()会更好。如果我不那么密集,我相信我会欣赏/理解何时仍然使用First()。
asfsadf

1
如果只想检索排序最高或最低的对象,则First()最有意义。例如,找到我的总价值最高的销售。Sales.OrderByDescending(s => s.TotalValue).First();
Mike Chamberlain

5
所有的评论看起来都有重要的区别。Find()是唯一的一种在命中数据库之前搜索上下文的方法。
Yaron Levi

5
另一点是在查询sql数据库时,Single或者SingleOrDefault将查询2条记录(限制2),而First或者FirstOrDefault将查询1 条记录(限制1)。
Bart Calixto 2015年

22

我总是倾向于使用FirstOrDefault。如果您真的想对性能保持挑剔,则应FirstOrDefault在EF中使用。在幕后SingleOrDefault使用了查询的顶部(2),因为它需要检查是否有第二行与条件匹配,如果匹配,则抛出异常。基本上,SingleOrDefault您的意思是如果查询返回的记录多于1条,则要引发异常。


5
您是否曾经测量过FirstOrDefault和之间的性能差异SingleOrDefault很大?我会说在大多数情况下这是过早的优化。
史蒂文

我倾向于使用,Single()或者SingleOrDefault()当我退货时,应该只存在一个。我这样做的原因是通过进行写得不好的查询来发现错误,这些错误返回的错误数量超过应有的失败。至少在我看来,这将有助于使系统中的数据保持一致。当然,这比较慢,但是我想它不会慢很多,我愿意为此付出代价。
mortb

15

这非常简单:Single返回单个项目,如果没有一个或多个项目,则抛出异常。First将返回第一个项目或没有项目时抛出。当没有项目时,FirstOrDefault将返回第一项或返回默认值(null在给定类型为引用类型的情况下)。

这是API应该具有的行为。但是请注意,基础实现可能具有不同的行为。尽管Entity Framework遵循了这一规定,但null调用时也可能返回像LLBLGen这样的O / RM First,这是非常奇怪的事情。这是设计师IMO做出的非常奇怪的决定。


谢谢史蒂文。我想我仍然想知道为什么您要使用另一个?我一直使用FirstOrDefault(),并对为什么我看到的许多新示例都切换到Single()感到好奇。是否有理由切换到Single()?是否还有其他人也可以完成相同的事情,我应该考虑考虑?
asfsadf

7
如果您希望代码“快速失败”,那么First()和Single()可以让您的代码更精确地说明期望的内容(否则它可能会失败)
Frank Schwieterman 2010年

3
我完全同意弗兰克。这也与意图传达有关。Single明确表示您只希望结果包含一个元素。
史蒂文

8

四种方法各有千秋。虽然您实际上只有两个不同的操作。

  • 首先-期望结果集中包含多个项目,请给我该集中的第一个项目。
  • 单身-希望得到单一结果,请给我该商品。

xxxxOrDefault()版本仅添加了“我不想将空结果集视为例外情况”。


好吧,所以在我看来First()很少派上用场。我很难提出Single()不是首选的方案。您碰巧有一个快速的下手吗?谢谢。
asfsadf

3
不幸的是,许多开发人员仅将First()或FirstOrDefault()用作防御措施,并认为当它真的有可能隐藏实际问题时,它将避免出现异常。
Matt H

3

另一方面,您可以按核心逻辑划分这些方法,如下所示:

  • 方法将直接查询数据库Single(),SingleOrDefault(),First(),FirstOrDefault()
  • 方法将在对数据库发出查询之前在缓存中执行搜索Find()

有关某些性能的详细信息,尤其是在第二种情况下,您可以在此处查看:https : //msdn.microsoft.com/zh-cn/data/hh949853.aspx?f=255&MSPPError=-2147217396#3

另外,在第一组中,您可以定义复杂的查询,但是使用Find()方法,您可以仅提供用于搜索的实体关键字。


0

Single()SingleOrDefault()通常用于诸如ID之类的唯一标识符,而First()FirstOrDefault()通常用于可能有多个结果但只需要“ Top 1”的查询

如果未返回任何结果,则Single()First()将引发异常,SingleOrDefault()FirstOrDefault()捕获该异常并返回null或default(ResultDataType)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.