考虑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?
Question
What conventions do you follow or suggest 在您的LINQ查询中决定使用 SingleOrDefault()
和 FirstOrDefault()
时?
13 回答
无论何时使用
SingleOrDefault
,您都清楚地声明查询最多只能产生一个结果 . 另一方面,当使用FirstOrDefault
时,查询可以返回任意数量的结果,但是您声明只需要第一个结果 .我个人发现语义非常不同,使用适当的语义,取决于预期的结果,提高了可读性 .
如果结果集返回0条记录:
SingleOrDefault
返回类型的默认值(例如,int的默认值为0)FirstOrDefault
返回该类型的默认值如果结果集返回1条记录:
SingleOrDefault
返回该记录FirstOrDefault
返回该记录如果结果集返回许多记录:
SingleOrDefault
抛出异常FirstOrDefault
返回第一条记录结论:
如果要在结果集包含许多记录时抛出异常,请使用
SingleOrDefault
.如果您总是想要1条记录,无论结果集包含什么,请使用
FirstOrDefault
有
一个语义上的区别
性能差异
两者之间 .
Semantical Difference:
FirstOrDefault
返回可能多次的第一项(如果不存在,则返回默认值) .SingleOrDefault
假定有一个项目并将其返回(如果不存在则为默认值) . 多个项目违反 Contract ,抛出异常 .Performance Difference
FirstOrDefault
通常更快,它会迭代直到找到元素,并且只有在找不到它时才需要迭代整个枚举 . 在许多情况下,很有可能找到一个项目 .SingleOrDefault
需要检查是否只有一个元素,因此总是迭代整个可枚举元素 . 确切地说,它会迭代,直到找到第二个元素并抛出异常 . 但在大多数情况下,没有第二个因素 .Conclusion
使用
FirstOrDefault
如果你不关心有多少项 or 当你无法负担检查唯一性时(例如在一个非常大的集合中) . 当您检查将项目添加到集合时的唯一性时,在搜索这些项目时再次检查它可能太昂贵了 .如果您不必过多关注性能,请使用
SingleOrDefault
并且要确保读者清楚单个项目的假设并在运行时检查 .在实践中,即使在假设单个项目的情况下,也经常使用
First
/FirstOrDefault
来提高性能 . 您还应该记住Single
/SingleOrDefault
可以提高可读性(因为它表明了单个项目的假设)和稳定性(因为它检查它)并适当地使用它 .没有人提到在SQL中翻译的FirstOrDefault执行TOP 1记录,而SingleOrDefault执行TOP 2,因为它需要知道是否有超过1条记录 .
For LINQ -> SQL:
SingleOrDefault
将生成如"select * from users where userid = 1"的查询
选择匹配记录,如果找到多条记录,则抛出异常
如果要基于主/唯一键列提取数据,请使用此选项
FirstOrDefault
将生成如"select top 1 * from users where userid = 1"的查询
选择第一个匹配的行
如果要基于非主/唯一键列提取数据,请使用此选项
在我的逻辑规定将为零或一个结果的情况下,我使用
SingleOrDefault
. 如果有更多,这是一个错误的情况,这是有帮助的 .SingleOrDefault:您说“最多”有一个项目与查询匹配或默认FirstOrDefault:您说的是“至少”有一个项目与查询匹配或默认
下次你需要选择大声说出来,你可能会明智地选择 . :)
在您的情况下,我会使用以下内容:
按ID == 5选择:在这里使用SingleOrDefault是可以的,因为你期望一个[或没有]实体,如果你有一个ID为5的实体,那就有问题了,绝对是值得的 .
当搜索名字等于“Bobby”的人时,可能会有不止一个(很可能我会想到),所以你既不应该使用Single也不要使用First,只需选择Where-operation(如果“Bobby”返回太多)实体,用户必须优化他的搜索或选择一个返回的结果)
创建日期的顺序也应该使用Where-operation执行(不太可能只有一个实体,排序没有多大用处;)但这意味着你想要排序所有实体 - 如果你只想要一个,使用FirstOrDefault,如果您有多个实体,则每次都会抛出 .
在你的上一个例子中:
是的,它确实 . 如果您尝试使用
SingleOrDefault()
并且查询结果超过记录,您将获得和异常 . 唯一一次你可以安全地使用SingleOrDefault()
就是你期望只有1而且只有1个结果......两者都是元素运算符,它们用于从序列中选择单个元素 . 但它们之间存在细微差别 . 如果满足多个元素,则FirstOrDefault()运算符将抛出异常,因为FirstOrDefault()不会抛出任何异常 . 这是一个例子 .
正如我现在所理解的那样,如果您要查询的是保证唯一的数据(即主键等数据库约束强制执行),_1086908将会很好 .
或者是否有更好的方法来查询主键 .
假设我的TableAcc有
我想查询
AccountNumber 987654
,我用回答中遗漏了一件事......
如果存在多个结果,则没有顺序的FirstOrDefault可以根据服务器正在使用的索引策略返回不同的结果 .
就个人而言,我无法忍受在代码中看到FirstOrDefault,因为据我所知,开发人员并不关心结果 . 尽管如此,它可以作为强制执行最新/最早的方式 . 我不得不纠正使用FirstOrDefault的粗心开发人员造成的很多问题 .
如果您使用
Find(key)
,这可以更快地检索结果,我不会't understand why you'使用FirstOrDefault(x=> x.ID == key)
. 如果您使用表的主键查询,则经验法则是始终使用Find(key)
.FirstOrDefault
应该用于谓词之类的东西,如(x=> x.Username == username)
等 .这不应该是一个downvote,因为问题的 Headers 不是特定于DB上的linq或列表/ IEnumerable等的Linq .