LINQ:何时使用SingleOrDefault与FirstOrDefault()一起使用过滤条件

时间:2009-11-16 23:59:33

标签: .net linq linq-to-sql

考虑IEnumerable扩展方法SingleOrDefault()FirstOrDefault()

MSDN documents that SingleOrDefault

  

返回序列的唯一元素,如果序列为空,则返回默认值;如果序列中有多个元素,则此方法抛出异常。

FirstOrDefault from MSDN(大概是在使用OrderBy()OrderByDescending()时根本没有),

  

返回序列的第一个元素

考虑一些示例查询,并不总是清楚何时使用这两种方法:

var someCust = db.Customers
.SingleOrDefault(c=>c.ID == 5); //unlikely(?) to be more than one, but technically COULD BE

var bobbyCust = db.Customers
.FirstOrDefault(c=>c.FirstName == "Bobby"); //clearly could be one or many, so use First?

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or does it matter?

问题

在您的LINQ查询中决定使用SingleOrDefault()FirstOrDefault()时,您遵循或建议的约定?

15 个答案:

答案 0 :(得分:530)

如果结果集返回0条记录:

  • SingleOrDefault返回该类型的默认值(例如,int的默认值为0)
  • FirstOrDefault返回类型
  • 的默认值

如果结果集返回1记录:

  • SingleOrDefault返回该记录
  • FirstOrDefault返回该记录

如果结果集返回许多记录:

  • SingleOrDefault抛出异常
  • FirstOrDefault返回第一条记录

结论:

如果您希望在结果集包含许多记录时抛出异常,请使用SingleOrDefault

如果您总是想要1条记录,无论结果集包含什么,请使用FirstOrDefault

答案 1 :(得分:422)

每当您使用SingleOrDefault时,您都明确指出查询最多只能产生单个结果。另一方面,当使用FirstOrDefault时,查询可以返回任意数量的结果,但是您声明只需要第一个结果。

我个人觉得语义非常不同,使用适当的语义,取决于预期的结果,提高了可读性。

答案 2 :(得分:226)

  • 语义差异
  • 性能差异

两者之间。

语义差异:

  • FirstOrDefault返回可能多次的第一项(如果不存在,则返回默认值)。
  • SingleOrDefault假设有一个项目并返回它(如果不存在则返回默认值)。多个项目违反合同,抛出异常。

效果差异

  • FirstOrDefault通常更快,它会迭代直到找到元素,并且只有在找不到它时才需要迭代整个枚举。在许多情况下,很有可能找到一个项目。

  • SingleOrDefault需要检查是否只有一个元素,因此总是迭代整个可枚举元素。确切地说,它会迭代,直到找到第二个元素并抛出异常。但在大多数情况下,没有第二个元素。

<强>结论

  • 使用FirstOrDefault如果你不在乎有多少项,当你无法负担检查唯一性时(例如在一个非常大的集合中)。当您检查将项目添加到集合时的唯一性时,在搜索这些项目时再次检查它可能太昂贵了。

  • 如果您不必过多关注性能,请使用SingleOrDefault,并确保读者明确单个项目的假设并在运行时进行检查。

实际上,即使在您假设单个项目的情况下,也经常使用First / FirstOrDefault来提高性能。您还应该记住,Single / SingleOrDefault可以提高可读性(因为它表示单个项目的假设)和稳定性(因为它会检查它)并正确使用它。

答案 3 :(得分:69)

没有人提到在SQL中翻译的FirstOrDefault执行TOP 1记录,而SingleOrDefault执行TOP 2,因为它需要知道是否有超过1条记录。

答案 4 :(得分:12)

对于LINQ - &gt; SQL:

SingleOrDefault

  • 将生成类似&#34;从用户ID = 1&#34;
  • 的用户中选择*的查询
  • 选择匹配记录,如果找到多条记录,则抛出异常
  • 如果您要根据主要/唯一键列
  • 获取数据,请使用此选项

FirstOrDefault

  • 将生成类似&#34的查询;从userid = 1&#34;
  • 的用户中选择前1 *
  • 选择第一个匹配的行
  • 如果您要根据非主要/唯一键列
  • 获取数据,请使用此选项

答案 5 :(得分:10)

在我的逻辑规定将为零或一个结果的情况下,我使用SingleOrDefault。如果有更多,这是一个错误的情况,这是有帮助的。

答案 6 :(得分:5)

SingleOrDefault:您说“最多”有一个项目与查询匹配或默认 FirstOrDefault:你说的是“至少”有一个项目与查询匹配或默认

下次你需要选择时大声说出来,你可能会明智地选择。 :)

答案 7 :(得分:4)

在您的情况下,我会使用以下内容:

通过ID == 5选择:在这里使用SingleOrDefault是可以的,因为你期望一个[或没有]实体,如果你有多个ID为5的实体,那就有错误,绝对值得例外。

当搜索名字等于“Bobby”的人时,可能会有多个(很可能我会想到),所以你既不应该使用Single也不要使用First,只需选择Where-operation(如果是“Bobby”)返回太多实体,用户必须优化他的搜索或选择一个返回的结果)

创建日期的顺序也应该使用Where-operation执行(不太可能只有一个实体,排序不会有太大用处;)但是这意味着你想要对所有实体进行排序 - 如果你只想要一个,使用FirstOrDefault,如果你有多个实体,Single会抛出。

答案 8 :(得分:3)

在你的上一个例子中:

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or doesn't matter?

是的。如果您尝试使用SingleOrDefault()并且查询结果超过了记录,那么您将获得并且异常。您唯一可以安全使用SingleOrDefault()的时间是您只期望1而且只有1个结果......

答案 9 :(得分:3)

两者都是元素运算符,它们用于从序列中选择单个元素。但它们之间存在细微差别。如果满足多个元素,则FirstOrDefault()运算符将抛出异常,因为FirstOrDefault()不会抛出任何异常。这是一个例子。

List<int> items = new List<int>() {9,10,9};
//Returns the first element of a sequence after satisfied the condition more than one elements
int result1 = items.Where(item => item == 9).FirstOrDefault();
//Throw the exception after satisfied the condition more than one elements
int result3 = items.Where(item => item == 9).SingleOrDefault();

答案 10 :(得分:1)

正如我现在所理解的那样,SingleOrDefault如果您要查询保证唯一的数据(即主键等数据库约束强制执行),将会很好。

或者有更好的方法来查询主键。

假设我的TableAcc有

AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.

我要查询AccountNumber 987654,我使用

var data = datacontext.TableAcc.FirstOrDefault(obj => obj.AccountNumber == 987654);

答案 11 :(得分:1)

我认为FirstOrDefault经常被滥用。在大多数情况下,当您过滤数据时,您要么期望返回匹配逻辑条件的元素集合,要么期望通过其唯一标识符(例如,用户,书籍,帖子等)来获得单个唯一元素。为什么我们甚至可以说FirstOrDefault()是一种代码味道,不是因为它有问题,而是因为它使用得太频繁了。 This blog post详细探讨了该主题。在大多数情况下,IMO SingleOrDefault()都是更好的选择,因此请小心此错误,并确保您使用最能清楚地代表您的合同和期望的方法。

答案 12 :(得分:0)

我询问Google在GitHub上使用不同方法的情况。这是通过为每种方法运行Google搜索查询并将查询限制为github.com域和.cs文件扩展名来完成的,方法是使用查询“ site:github.com file:cs ...”

似乎First *方法比Single *方法更常用。

| Method               | Results |
|----------------------|---------|
| FirstAsync           |     315 |
| SingleAsync          |     166 |
| FirstOrDefaultAsync  |     357 |
| SingleOrDefaultAsync |     237 |
| FirstOrDefault       |   17400 |
| SingleOrDefault      |    2950 |

答案 13 :(得分:0)

本质上,这为您提供了某种清理数据的验证,如果您选择一个而不是另一个,它将同时提供数据,但 SingleOrDefault 会让您意识到当您期望的数据应该只有 1 个结果时并吐出更多 1 然后你需要看看为什么你的存储过程或查询会导致这样的重复项无论如何在查询中永远不会好。

答案 14 :(得分:-1)

回复中遗漏了一件事......

如果有多个结果,没有订单的FirstOrDefault可以根据服务器正在使用的索引策略返回不同的结果。

就我个人而言,我无法忍受在代码中看到FirstOrDefault,因为据我所知,开发人员并不关心结果。尽管如此,它可以作为强制执行最新/最早的方式。我不得不纠正使用FirstOrDefault的粗心开发人员造成的很多问题。