考虑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将是很好的,如果你正在查询数据,保证是唯一的,即强制的DB约束,如主键。
或者是否有更好的方法来查询主键。
假设我的TableAcc有
AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.
和我想查询一个AccountNumber 987654,我使用
var data = datacontext.TableAcc.FirstOrDefault(obj => obj.AccountNumber == 987654);
如果结果集返回0条记录:
SingleOrDefault返回类型的默认值(例如int的默认值为0)
FirstOrDefault返回类型的默认值
如果结果集返回1条记录:
SingleOrDefault返回该记录
FirstOrDefault返回该记录
如果你的结果集返回很多记录:
SingleOrDefault抛出异常
FirstOrDefault返回第一条记录
结论:
如果希望在结果集包含许多记录时抛出异常,请使用SingleOrDefault。
如果无论结果集包含什么,您总是想要1条记录,请使用FirstOrDefault
有
语义上的差异
性能差异
两者之间。
语义的区别:
FirstOrDefault返回可能有多个的第一项(如果不存在则返回default)。
SingleOrDefault假设有一个单项并返回它(如果不存在则返回default)。多个项目违反合同,抛出异常。
性能差异
FirstOrDefault通常更快,它迭代直到找到元素,只有在找不到元素时才迭代整个枚举对象。在许多情况下,有很大的可能性找到一个项目。
SingleOrDefault需要检查是否只有一个元素,因此总是迭代整个枚举对象。准确地说,它迭代直到找到第二个元素并抛出异常。但在大多数情况下,没有第二个元素。
结论
如果你不关心有多少项,或者当你无法负担检查唯一性的费用时(例如在一个非常大的集合中),请使用FirstOrDefault。当您在将项添加到集合时检查唯一性时,在搜索这些项时再次检查它可能代价太大。
如果您不需要太关心性能,并且希望确保单个项的假设对读者来说是清楚的,并在运行时进行检查,则使用SingleOrDefault。
在实践中,即使在假设单个项的情况下,也经常使用First / FirstOrDefault来提高性能。您仍然应该记住,Single / SingleOrDefault可以提高可读性(因为它声明了单个项的假设)和稳定性(因为它检查了它),并适当地使用它。