关于.NET:Linq:何时使用带有筛选条件的singleOrDefault与firstOrDefault()

LINQ: When to use SingleOrDefault vs. FirstOrDefault() with filtering criteria

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

msdn文件说明SingleOrDefault

Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.

鉴于来自msdn的FirstOrDefault(可能在使用OrderBy()OrderByDescending()或根本不使用时)

Returns the first element of a sequence

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

1
2
3
4
5
6
7
8
9
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()时,您遵循或建议什么约定?


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

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

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

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

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

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

结论:

如果希望在结果集包含多个记录时引发异常,请使用SingleOrDefault

如果不管结果集包含什么,您总是需要1条记录,请使用FirstOrDefault


whenever你使用SingleOrDefault,你明确的状态,query应该作为一个结果,在美元现在在单一的一个结果。在另一方面,当FirstOrDefault用,query可以返回任何量的结果,但你的状态,你只想要的第一人。 P / < >

我personally找到的semantics非常不同的和使用的一个适当的情况下,取决于上的expected结果,提高了readability。 P / < >


有 P / < >

  • 在semantical都
  • 的性能都

之间的两个。 P / < >

semantical都: P / < >

  • FirstOrDefaultreturns第一item of potentially多(或违约,如果没有exists)。
  • SingleOrDefaultassumes,有单一的item和returns它(或违约,如果没有exists)。多个项目是在violation的合同,一个例外是thrown。

性能都 P / < >

  • FirstOrDefault也usually更快,它iterates直到它的finds元和腹部只到iterate整个enumerable当它没有被发现它。在许多案例,有高的概率找到一个item。 P / < >

  • SingleOrDefault需要去检查,如果有只有一元和therefore总是iterates整个enumerable。要精确,它iterates直到它finds的二元和throws一个例外。但在现在cases,没有第二元。 P / < >

结论 P / < >

  • 使用FirstOrDefault如果你不在乎有多少项目或当你找不afford检查uniqueness(例如在一个非常大的集合)。当你检查uniqueness C的项目添加到收集的,它可能太昂贵到检查它的时候再找这些项目。 P / < >

  • 使用SingleOrDefault如果你不用在乎太多的性能和想让相信的assumption of item的单一明确的读者和检查runtime美元。 P / < >

在练习,你使用First/ FirstOrDefaultoften甚至在例当你为此承担的单一项目,到improve性能。你应该还记得,Single/ SingleOrDefault可以improve readability(因为它美国的assumption的单一item)和稳定性(因为它-它)和使用它appropriately。 P / < >


没有人提到在SQL中转换的first或default会做前1条记录,而singleordefault会做前2条记录,因为它需要知道是否有超过1条记录。


对于LINQ->SQL:

单一违约

  • 将生成类似"select*from users where userid=1"的查询
  • 选择匹配的记录,如果找到多个记录,则引发异常
  • 如果要根据主键/唯一键列提取数据,则使用

首次违约

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


我用SingleOrDefault在situations在我的dictates逻辑,将无论是零或一个结果。如果有更多的,它是一个错误的情况,这是helpful。 P / < >


singleordefault:你是说,"在现在"有一个item或"query或违约 firstordefault:你是说,"至少有一个item"或"query或违约 P / < >

说,联盟的下一个时间,你需要选择你要明智的选择成为可能。:) P / < >


在你的案例,我会用以下的: P / < >

选择id = = = 5:很好用singleordefault到这里,因为你没有想到一个[或] entity,如果你有超过一个entity id与5,有什么错误和例外绝对是值得的。 P / < >

当找人的第一个名字equals"鲍比",*能有超过一个(很可能)会认为),所以你应该neither也使用单一的第一选择,只是与你在操作上(如果"鲍比"returns太多的实体,用户到他的腹部refine搜索或选择一个乐队结果returned) P / < >

秩序由创作的日期应该也在performed与我在操作上的(unlikely到有只有一个实体,sorting不会停止使用之多;然而这implies)你想要的所有的实体sorted -如果你想要的只是一个单一的使用,firstordefault,会把每一个时间,如果你有超过一个实体。 P / < >


两者都是元素操作符,用于从序列中选择单个元素。但它们之间有一个微小的区别。如果满足以下条件,则singleOrDefault()运算符将引发异常:as firstOrDefault()不会对同一个元素引发任何异常。下面是例子。

1
2
3
4
5
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();


在你的最后一个例子: P / < >

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

是的,它确实没有。如果你试着用SingleOrDefault()和query结果记录在比你会得到和例外。唯一的时间你可以安全的使用SingleOrDefault()还当你是唯一的期待和1只1的结果…… P / < >


因此,我现在了解到,如果您查询的数据保证是唯一的,即由数据库约束(如主键)强制执行,那么SingleOrDefault将是很好的。

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

假设我的TableAcc

1
2
3
4
5
AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.

我想查询一个AccountNumber 987654,我用

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


回答中遗漏了一件事……

如果有多个结果,没有order by的first或default可以返回不同的结果,而服务器使用的索引策略正是基于这些结果。

就我个人而言,我无法忍受在代码中看到first或efault,因为对我来说,它表示开发人员不关心结果。尽管它可以作为强制执行最新/最早版本的一种方式,但它还是有帮助的。我不得不纠正许多由使用first或default的粗心开发人员引起的问题。


我不明白你为什么要使用FirstOrDefault(x=> x.ID == key),如果你使用Find(key),那么检索结果会更快。如果使用表的主键进行查询,则经验法则是始终使用Find(key)FirstOrDefault应用于(x=> x.Username == username)等谓词。

由于问题的标题不特定于DB上的LINQ或要列出的LINQ/IEnumerable等,因此不应投反对票。