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


当前回答

我使用SingleOrDefault的情况下,我的逻辑将是零或一个结果。如果有更多,这是一个错误的情况,这是有帮助的。

其他回答

无论何时使用SingleOrDefault,都明确声明查询最多只能产生一个结果。另一方面,当使用FirstOrDefault时,查询可以返回任意数量的结果,但您声明只想要第一个结果。

我个人认为语义非常不同,根据预期结果使用适当的语义可以提高可读性。

对于LINQ -> SQL:

SingleOrDefault

将生成查询,如“select TOP 2 * from users where userid = 1” 选择匹配的记录,如果发现多个记录则抛出异常 如果基于主键/唯一键列获取数据,则使用

FirstOrDefault

将生成类似于“select userid = 1的用户中的top 1 *”的查询 选择第一个匹配的行 如果基于非主键/唯一键列获取数据,则使用

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

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

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

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

我使用SingleOrDefault的情况下,我的逻辑将是零或一个结果。如果有更多,这是一个错误的情况,这是有帮助的。

在回答中漏掉了一件事....

如果有多个结果,没有排序by的FirstOrDefault可以根据服务器碰巧使用的索引策略返回不同的结果。

就我个人而言,我无法忍受在代码中看到FirstOrDefault,因为对我来说,这表明开发人员不关心结果。通过命令,它可以作为一种强制执行最新/最早的方式。我不得不纠正许多由于粗心的开发人员使用FirstOrDefault而引起的问题。