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

MSDN文档SingleOrDefault:

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

而来自MSDN的FirstOrDefault(假设在使用OrderBy()或orderbydescent()或根本不使用时),

返回序列的第一个元素

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

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()时,你遵循或建议什么约定?


当前回答

In my opinion FirstOrDefault is being overused a lot. In the majority of the cases when you’re filtering data you would either expect to get back a collection of elements matching the logical condition or a single unique element by its unique identifier – such as a user, book, post etc... That’s why we can even get as far as saying that FirstOrDefault() is a code smell not because there is something wrong with it but because it’s being used way too often. This blog post explores the topic in details. IMO most of the times SingleOrDefault() is a much better alternative so watch out for this mistake and make sure you use the most appropriate method that clearly represents your contract and expectations.

其他回答

没有人提到SQL中转换的FirstOrDefault执行TOP 1记录,而SingleOrDefault执行TOP 2记录,因为它需要知道是否有多个记录。

所以,正如我现在所理解的,SingleOrDefault将是很好的,如果你正在查询数据,保证是唯一的,即强制的DB约束,如主键。

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

假设我的TableAcc有

AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.

和我想查询一个AccountNumber 987654,我使用

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

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

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

从本质上讲,这给了你某种验证来清理你的数据,如果你选择其中一个,它会同时给出数据,但SingleOrDefault会让你意识到,当你期望的数据应该只有1个结果,并吐出更多的1,那么你需要看看为什么你的存储过程或查询导致这样,重复的项目在查询中从来都不好。

两者都是元素操作符,用于从序列中选择单个元素。但是它们之间有一个微小的区别。SingleOrDefault()操作符将在多个元素满足条件时抛出异常,而as 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();