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


当前回答

语义上的差异 性能差异

两者之间。

语义的区别:

FirstOrDefault返回可能有多个的第一项(如果不存在则返回default)。 SingleOrDefault假设有一个单项并返回它(如果不存在则返回default)。多个项目违反合同,抛出异常。

性能差异

FirstOrDefault通常更快,它迭代直到找到元素,只有在找不到元素时才迭代整个枚举对象。在许多情况下,有很大的可能性找到一个项目。 SingleOrDefault需要检查是否只有一个元素,因此总是迭代整个枚举对象。准确地说,它迭代直到找到第二个元素并抛出异常。但在大多数情况下,没有第二个元素。

结论

如果你不关心有多少项,或者当你无法负担检查唯一性的费用时(例如在一个非常大的集合中),请使用FirstOrDefault。当您在将项添加到集合时检查唯一性时,在搜索这些项时再次检查它可能代价太大。 如果您不需要太关心性能,并且希望确保单个项的假设对读者来说是清楚的,并在运行时进行检查,则使用SingleOrDefault。

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

其他回答

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

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

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

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

如果你的结果集返回很多记录:

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

结论:

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

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

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

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

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

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

在你的情况下,我会使用以下方法:

select by ID==5:在这里使用SingleOrDefault是可以的,因为你希望有一个[或没有]实体,如果你有多个ID为5的实体,那就有问题了,肯定值得异常处理。

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

按创建日期的顺序也应该执行一个where操作(不太可能只有一个实体,排序不会有太大的用处;)这意味着你想要所有的实体排序-如果你想要一个,使用FirstOrDefault, Single会抛出每次如果你有多个实体。