LINQ:何时使用SingleOrDefault与FirstOrDefault()一起使用过滤条件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LINQ:何时使用SingleOrDefault与FirstOrDefault()一起使用过滤条件相关的知识,希望对你有一定的参考价值。
考虑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()
时,您遵循或建议的约定是什么?
每当您使用SingleOrDefault
时,您都明确指出查询最多只能产生一个结果。另一方面,当使用FirstOrDefault
时,查询可以返回任何数量的结果,但是您声明只需要第一个结果。
我个人发现语义非常不同,使用适当的语义,取决于预期的结果,提高了可读性。
两者都是元素运算符,它们用于从序列中选择单个元素。但它们之间存在细微差别。如果满足多个元素,则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();
正如我现在所理解的那样,如果您要查询的是保证唯一的数据(即主键等数据库约束强制执行),SingleOrDefault
会很好。
或者是否有更好的方法来查询主键。
假设我的TableAcc有
AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.
我想查询AccountNumber 987654
,我用
var data = datacontext.TableAcc.FirstOrDefault(obj => obj.AccountNumber == 987654);
我向Google询问了GitHub上不同方法的用法。这是通过为每个方法运行Google搜索查询并使用查询“site:github.com file:cs ...”将查询限制到github.com域和.cs文件扩展名来完成的。
看起来First *方法比Single *方法更常用。
| Method | Results |
|----------------------|---------|
| FirstAsync | 315 |
| SingleAsync | 166 |
| FirstOrDefaultAsync | 357 |
| SingleOrDefaultAsync | 237 |
| FirstOrDefault | 17400 |
| SingleOrDefault | 2950 |
回答中遗漏了一件事......
如果存在多个结果,则没有顺序的FirstOrDefault可以根据服务器正在使用的索引策略返回不同的结果。
就个人而言,我无法忍受在代码中看到FirstOrDefault,因为据我所知,开发人员并不关心结果。尽管如此,它可以作为强制执行最新/最早的方式。我不得不纠正使用FirstOrDefault的粗心开发人员造成的很多问题。
我不明白为什么你使用FirstOrDefault(x=> x.ID == key)
,如果你使用Find(key)
可以更快地检索结果。如果您使用表的主键查询,经验法则是始终使用Find(key)
。 FirstOrDefault
应该用于像(x=> x.Username == username)
等谓词。
这不应该是一个downvote,因为问题的标题不是特定于DB上的linq或列表/ IEnumerable等的Linq。
如果结果集返回0条记录:
SingleOrDefault
返回类型的默认值(例如,int的默认值为0)FirstOrDefault
返回该类型的默认值
如果结果集返回1条记录:
SingleOrDefault
返回该记录FirstOrDefault
返回该记录
如果结果集返回许多记录:
SingleOrDefault
抛出一个例外FirstOrDefault
返回第一条记录
结论:
如果要在结果集包含许多记录时抛出异常,请使用SingleOrDefault
。
如果您总是想要1条记录,无论结果集包含什么,请使用FirstOrDefault
有
- 语义差异
- 性能差异
两者之间。
语义差异:
FirstOrDefault
返回可能多个的第一项(如果不存在,则返回默认值)。SingleOrDefault
假设有一个项目并返回它(如果不存在则默认)。多个项目违反合同,抛出异常。
性能差异
FirstOrDefault
通常更快,它迭代直到找到元素,并且只有在它找不到时才需要迭代整个枚举。在许多情况下,很有可能找到一个项目。SingleOrDefault
需要检查是否只有一个元素,因此总是迭代整个可枚举元素。确切地说,它会迭代,直到找到第二个元素并抛出异常。但在大多数情况下,没有第二个因素。
结论
- 如果您不关心有多少项目或者您无法负担检查唯一性(例如在非常大的集合中),请使用
FirstOrDefault
。当您检查将项目添加到集合时的唯一性时,在搜索这些项目时再次检查它可能太昂贵了。 - 如果您不必过多关注性能,请使用
SingleOrDefault
,并希望确保读者清楚单个项目的假设并在运行时检查。
在实践中,即使在假设单个项目的情况下,也经常使用First
/ FirstOrDefault
来提高性能。您还应该记住,Single
/ SingleOrDefault
可以提高可读性(因为它表示单个项目的假设)和稳定性(因为它检查它)并适当地使用它。
没有人提到在SQL中翻译的FirstOrDefault执行TOP 1记录,而SingleOrDefault执行TOP 2,因为它需要知道是否有超过1条记录。
对于LINQ - > SQL:
的SingleOrDefault
- 将生成类似“select * from user where userid = 1”的查询
- 选择匹配记录,如果找到多条记录,则抛出异常
- 如果要基于主/唯一键列提取数据,请使用此选项
FirstOrDefault
- 将生成查询,例如“从userid = 1的用户中选择前1 *”
- 选择第一个匹配的行
- 如果要基于非主/唯一键列提取数据,请使用此选项
我使用SingleOrDefault
的情况下我的逻辑指示将是零或一个结果。如果有更多,这是一个错误的情况,这是有帮助的。
SingleOrDefault:您说“最多”有一个项目与查询匹配或默认FirstOrDefault:您说的是“至少”有一个项目与查询匹配或默认
下次你需要选择大声说出来,你可能会明智地选择。 :)
在您的情况下,我会使用以下内容:
按ID == 5选择:在这里使用SingleOrDefault是可以的,因为你期望一个[或没有]实体,如果你有多个ID为5的实体,那就有错误,绝对值得特别。
当搜索名字等于“Bobby”的人时,可能会有不止一个(很可能我会想到),所以你既不应该使用Single也不要使用First,只需选择Where-operation(如果“Bobby”返回太多)实体,用户必须优化他的搜索或选择一个返回的结果)
创建日期的顺序也应该使用Where-operation执行(不太可能只有一个实体,排序没有多大用处;)但是这意味着你想要排序所有实体 - 如果你只想要一个,请使用FirstOrDefault,如果您有多个实体,则每次都会抛出。
在你的上一个例子中:
var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or doesn't matter?
是的,它确实。如果您尝试使用SingleOrDefault()
并且查询结果超过记录,您将获得和异常。唯一一次你可以安全地使用SingleOrDefault()
是当你只期望1和只有1结果...
以上是关于LINQ:何时使用SingleOrDefault与FirstOrDefault()一起使用过滤条件的主要内容,如果未能解决你的问题,请参考以下文章
何时使用 .First 以及何时将 .FirstOrDefault 与 LINQ 一起使用?
Linq中SingleOrDefaultFirstOrDefault的用法