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

p.c*_*ell 487 .net linq linq-to-sql

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

MSDN文件表明SingleOrDefault:

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

FirstOrDefault从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?
Run Code Online (Sandbox Code Playgroud)

你遵循或暗示什么约定决定要使用时SingleOrDefault(),并FirstOrDefault()在您的LINQ查询?

Ale*_*lex 563

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

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

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

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

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

  • SingleOrDefault 抛出一个例外
  • FirstOrDefault 返回第一条记录

结论:

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

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

  • 我建议实际上很少需要例外,因此大多数时候FirstOrDefault都是首选.我知道案件不会经常存在. (6认同)
  • 我也喜欢这个答案.特别是考虑到在某些情况下你实际上想要抛出异常,因为你打算在其他地方正确处理这种罕见的情况,而不是假装它不会发生.当你想要这个例外时,你会清楚地说明这一点,同时也迫使其他人只需要处理这个问题,从而使整个系统更加健壮. (4认同)

Bry*_*ard 448

无论何时使用SingleOrDefault,您都清楚地声明查询最多只能产生一个结果.另一方面,当FirstOrDefault使用时,查询可以返回任何数量的结果,但是您声明只需要第一个结果.

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

  • 一个非常重要的区别是,如果对具有多个元素的序列使用SingleOrDefault,则会抛出异常. (152认同)
  • @kami如果没有抛出异常,它就像FirstOrDefault.唯一的例外是SingleOrDefault.好点提出来,并指出差异的棺材. (17认同)
  • 我必须说,从性能方面来看,FirstOrDefault的工作速度比SingleOrDefault快10倍,使用List <MyClass>的9,000,000个元素,类包含2个整数,Func包含对这两个整数的搜索.在循环中搜索200次在var v = list.SingleOrDefault(x => x.Id1 == i && x.Id2 == i)上花了22秒; 和var v = list.FirstOrDefault(x => x.Id1 == i && x.Id2 == i); 大约3秒钟 (13认同)
  • @BitsandBytesHandyman如果SignleOrDefault在序列包含多个项目时没有抛出异常,则它的行为与FirstOrDefault完全不同.FirstOrDefault返回第一个项,如果序列为空,则返回null.SingleOrDefault应该返回唯一的项,如果序列为空,或者如果它包含多个项,则返回null,而不会抛出异常. (6认同)
  • @RSW是的,我知道这一点.仔细阅读我的评论,我说的是SingleOrDefault应该做什么,而不是它做什么.但当然,它应该做的是非常主观的.对我来说,"SomethingOrDefault"模式意味着:获得"Something"的价值.如果"Something"无法返回值,则返回默认值.这意味着即使在"Something"会引发异常的情况下也应该返回默认值.因此,Single会抛出异常,SingleOrDefault应该以我的观点返回默认值. (2认同)
  • @RSW 继续我之前的评论:但是在序列中有多个项目的情况下,SingleOrDefault 的行为与 Single 完全一样。他们都抛出异常。在我看来,这看起来有点奇怪,但我理解记录在案的行为背后的基本原理。也许,我期望从 SignleOrDefault 得到的行为应该在一个叫做 OnlyOrDefault 的方法中实现,或者类似的东西,它应该返回序列的唯一项,或者在任何其他情况下(零,或多于一项)它应该返回默认值。 (2认同)

Ste*_*ger 235

  • 语义差异
  • 性能差异

两者之间.

语义差异:

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

性能差异

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

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

结论

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

  • 使用SingleOrDefault如果你没有在乎太多性能,并希望确保单个项目的前提是明确的读者,并在运行时检查.

在实践中,即使在假设单个项目的情况下,也经常使用First/ FirstOrDefault来提高性能.您仍然应该记住Single/ SingleOrDefault可以提高可读性(因为它表示单个项目的假设)和稳定性(因为它检查它)并适当地使用它.

  • +1*"或当您无法负担检查唯一性时(例如,在非常大的集合中)."*.我在寻找这个.我还会在插入时添加**强制唯一性,或者/和设计**而不是在进行查询时! (14认同)
  • @memetolsen考虑使用LINQ to SQL的两个代码吐出 - FirstOrDefault使用Top 1. SingleOrDefault使用Top 2. (3认同)

sha*_*lke 71

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

  • 当我通过LinqPad和VS运行SingleOrDefault时,我从未得到SELECT TOP 2,使用FirstOrDefault我能够获得SELECT TOP 1,但据我所知,你没有得到SELECT TOP 2. (3认同)
  • EF Core 2.1 将 FirstOrDefault 转换为 SELECT TOP(1),SingleOrDefault 转换为 SELECT TOP(2) (3认同)

Pra*_*ash 17

对于LINQ - > SQL:

的SingleOrDefault

  • 将生成类似"select*from user where userid = 1"的查询
  • 选择匹配记录,如果找到多条记录,则抛出异常
  • 如果要基于主/唯一键列提取数据,请使用此选项

FirstOrDefault

  • 将生成查询,例如"从userid = 1的用户中选择前1*"
  • 选择第一个匹配的行
  • 如果要基于非主/唯一键列提取数据,请使用此选项


spe*_*der 10

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

  • 我经常发现SingleOrDefault()突出显示我没有对结果集应用正确过滤的情况,或者底层数据中存在重复问题的情况.通常情况下,我发现自己使用Single()和SingleOrDefault()而不是First()方法. (3认同)

Oll*_*lli 5

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

select by ID==5:这里使用 SingleOrDefault 是可以的,因为您期望一个[或没有]实体,如果您有多个 ID 为 5 的实体,则存在错误并且绝对值得例外。

当搜索名字等于“Bobby”的人时,可能会有多个(我认为很可能),所以你不应该使用 Single 或 First,只需使用Where操作进行选择(如果“Bobby”返回太多实体,用户必须优化其搜索或选择返回的结果之一)

按创建日期排序还应该使用Where操作执行(不太可能只有一个实体,排序没有多大用处;)但这意味着您希望对所有实体进行排序 - 如果您只想要一个实体,请使用FirstOrDefault,如果你有多个实体,每次都会抛出 Single。

  • 我不同意。如果您的数据库 ID 是主键,则数据库已经强制执行唯一性。浪费 CPU 周期来检查数据库是否正在执行每个查询的工作是愚蠢的。 (4认同)

小智 5

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

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

  • 实际上没有结果是完全可以接受的`FirstOrDefault.更正确:`FirstOrDefault` =任意数量的结果,但我只关心第一个,可能也没有结果.`SingleOrDefault` =有1或0个结果,如果有更多结果意味着某处出现错误.`First` =至少有一个结果,我想要它.`Single` =正好有1个结果,没有更多,没有更少,我想要那个. (5认同)