首页 文章

LINQ:何时使用SingleOrDefault与FirstOrDefault()一起使用过滤条件

提问于
浏览
423

考虑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?

Question

What conventions do you follow or suggest 在您的LINQ查询中决定使用 SingleOrDefault()FirstOrDefault() 时?

13 回答

  • 4

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

    我个人发现语义非常不同,使用适当的语义,取决于预期的结果,提高了可读性 .

  • 504

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

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

    • FirstOrDefault 返回该类型的默认值

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

    • SingleOrDefault 返回该记录

    • FirstOrDefault 返回该记录

    如果结果集返回许多记录:

    • SingleOrDefault 抛出异常

    • FirstOrDefault 返回第一条记录

    结论:

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

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

  • 7

    • 一个语义上的区别

    • 性能差异

    两者之间 .

    Semantical Difference:

    • FirstOrDefault 返回可能多次的第一项(如果不存在,则返回默认值) .

    • SingleOrDefault 假定有一个项目并将其返回(如果不存在则为默认值) . 多个项目违反 Contract ,抛出异常 .

    Performance Difference

    • FirstOrDefault 通常更快,它会迭代直到找到元素,并且只有在找不到它时才需要迭代整个枚举 . 在许多情况下,很有可能找到一个项目 .

    • SingleOrDefault 需要检查是否只有一个元素,因此总是迭代整个可枚举元素 . 确切地说,它会迭代,直到找到第二个元素并抛出异常 . 但在大多数情况下,没有第二个因素 .

    Conclusion

    • 使用 FirstOrDefault 如果你不关心有多少项 or 当你无法负担检查唯一性时(例如在一个非常大的集合中) . 当您检查将项目添加到集合时的唯一性时,在搜索这些项目时再次检查它可能太昂贵了 .

    • 如果您不必过多关注性能,请使用 SingleOrDefault 并且要确保读者清楚单个项目的假设并在运行时检查 .

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

  • 388

    没有人提到在SQL中翻译的FirstOrDefault执行TOP 1记录,而SingleOrDefault执行TOP 2,因为它需要知道是否有超过1条记录 .

  • 1

    For LINQ -> SQL:

    SingleOrDefault

    • 将生成如"select * from users where userid = 1"的查询

    • 选择匹配记录,如果找到多条记录,则抛出异常

    • 如果要基于主/唯一键列提取数据,请使用此选项

    FirstOrDefault

    • 将生成如"select top 1 * from users where userid = 1"的查询

    • 选择第一个匹配的行

    • 如果要基于非主/唯一键列提取数据,请使用此选项

  • 3

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

  • -7

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

    下次你需要选择大声说出来,你可能会明智地选择 . :)

  • 218

    在您的情况下,我会使用以下内容:

    按ID == 5选择:在这里使用SingleOrDefault是可以的,因为你期望一个[或没有]实体,如果你有一个ID为5的实体,那就有问题了,绝对是值得的 .

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

    创建日期的顺序也应该使用Where-operation执行(不太可能只有一个实体,排序没有多大用处;)但这意味着你想要排序所有实体 - 如果你只想要一个,使用FirstOrDefault,如果您有多个实体,则每次都会抛出 .

  • 9

    在你的上一个例子中:

    var latestCust = db.Customers
    .OrderByDescending(x=> x.CreatedOn)
    .FirstOrDefault();//Single or First, or doesn't matter?
    

    是的,它确实 . 如果您尝试使用 SingleOrDefault() 并且查询结果超过记录,您将获得和异常 . 唯一一次你可以安全地使用 SingleOrDefault() 就是你期望只有1而且只有1个结果......

  • 5

    两者都是元素运算符,它们用于从序列中选择单个元素 . 但它们之间存在细微差别 . 如果满足多个元素,则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();
    
  • 0

    正如我现在所理解的那样,如果您要查询的是保证唯一的数据(即主键等数据库约束强制执行),_1086908将会很好 .

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

    假设我的TableAcc有

    AccountNumber - Primary Key, integer
    AccountName
    AccountOpenedDate
    AccountIsActive
    etc.
    

    我想查询 AccountNumber 987654 ,我用

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

    回答中遗漏了一件事......

    如果存在多个结果,则没有顺序的FirstOrDefault可以根据服务器正在使用的索引策略返回不同的结果 .

    就个人而言,我无法忍受在代码中看到FirstOrDefault,因为据我所知,开发人员并不关心结果 . 尽管如此,它可以作为强制执行最新/最早的方式 . 我不得不纠正使用FirstOrDefault的粗心开发人员造成的很多问题 .

  • 3

    如果您使用 Find(key) ,这可以更快地检索结果,我不会't understand why you'使用 FirstOrDefault(x=> x.ID == key) . 如果您使用表的主键查询,则经验法则是始终使用 Find(key) . FirstOrDefault 应该用于谓词之类的东西,如 (x=> x.Username == username) 等 .

    这不应该是一个downvote,因为问题的 Headers 不是特定于DB上的linq或列表/ IEnumerable等的Linq .

相关问题