代码之家  ›  专栏  ›  技术社区  ›  p.campbell

Linq:何时使用带有筛选条件的singleOrDefault与firstOrDefault()。

  •  443
  • p.campbell  · 技术社区  · 15 年前

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

    问题

    你遵循或建议什么惯例 决定使用时 单个或默认值() 第一个或默认值() 在你的LINQ查询中?

    13 回复  |  直到 6 年前
        1
  •  403
  •   Wai Ha Lee captain-yossarian from Ukraine    6 年前

    无论何时使用 SingleOrDefault ,您清楚地声明查询最多应导致 单一的 结果。另一方面,当 FirstOrDefault 如果使用,查询可以返回任意数量的结果,但您声明只需要第一个结果。

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

        2
  •  518
  •   shashwat    11 年前

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

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

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

    • 单一违约 返回该记录
    • 首次违约 返回该记录

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

    • 单一违约 引发异常
    • 首次违约 返回第一条记录

    结论:

    如果希望在结果集包含多个记录时引发异常,请使用 单一违约 .

    如果无论结果集包含什么,始终需要1条记录,请使用 首次违约

        3
  •  225
  •   Stefan Steinegger    12 年前

    • 语义差异
    • 性能差异

    在两者之间。

    语义差异:

    • FirstOrDefault 返回第一个可能是多个的项(如果不存在,则返回默认值)。
    • SingleOrDefault 假定存在单个项并返回它(如果不存在则默认)。多个项目违反合同,引发异常。

    性能差异

    • 首次违约 通常更快,它迭代直到找到元素,并且只在找不到元素时迭代整个可枚举的元素。在许多情况下,找到物品的可能性很高。

    • 单一违约 需要检查是否只有一个元素,因此始终迭代整个可枚举元素。更准确地说,它迭代直到找到第二个元素并抛出异常。但在大多数情况下,没有第二个元素。

    结论

    • 使用 首次违约 如果你不在乎有多少东西 当您负担不起检查唯一性的费用时(例如在一个非常大的集合中)。当您检查向集合中添加项的唯一性时,在搜索这些项时再次检查它可能太贵了。

    • 使用 单一违约 如果您不必太在意性能,并且希望确保读者能够清楚地了解单个项目的假设,并在运行时进行检查。

    在实践中,你使用 First / 首次违约 通常,即使在假设单个项目时,为了提高性能。你应该还记得 Single / 单一违约 可以提高可读性(因为它声明了单个项目的假设)和稳定性(因为它检查了它),并适当地使用它。

        4
  •  68
  •   shalke    14 年前

    没有人提到,在SQL中转换的first或default是前1条记录,而single或default是前2条记录,因为它需要知道是否有超过1条记录。

        5
  •  11
  •   Prakash    7 年前

    对于Linq->SQL:

    单一违约

    • 将生成类似“select*from users where userid=1”的查询
    • 选择匹配的记录,如果找到多个记录,则引发异常
    • 如果要根据主键/唯一键列提取数据,则使用

    首次违约

    • 将生成类似“从userid=1的用户中选择前1个*的查询”
    • 选择第一个匹配行
    • 如果要基于非主键/唯一键列提取数据,请使用
        6
  •  10
  •   spender    15 年前

    我用 SingleOrDefault 在我的逻辑指示结果为零或一的情况下。如果还有更多,这是一个错误情况,这是有帮助的。

        7
  •  5
  •   Steven    15 年前

    singleOrDefault:您的意思是“最多”有一个项目匹配查询或默认值。 first或default:您的意思是至少有一个项目与查询或默认值匹配。

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

        8
  •  4
  •   Olli    15 年前

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

    按id==5选择:这里可以使用single或default,因为您希望有一个[或无]实体,如果有多个id为5的实体,则会出现错误,绝对值得异常处理。

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

    按创建日期排序还应使用where操作(不太可能只有一个实体,排序不会有太大的用处;)但这意味着您希望对所有实体进行排序-如果只需要一个实体,请使用first或default,如果有多个实体,则每次都会抛出single。

        9
  •  3
  •   bytebender    15 年前

    在上一个示例中:

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

    是的。如果你想用 SingleOrDefault() 查询的结果将超过您将得到的记录和异常。你唯一可以安全使用的时间 单个或默认值() 当您只期望1个结果时…

        10
  •  3
  •   karlingen    8 年前

    两者都是元素操作符,用于从序列中选择单个元素。但它们之间有一个微小的区别。如果满足以下条件,则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();
    
        11
  •  1
  •   Nikolay Kostov    10 年前

    我现在明白了, SingleOrDefault 如果您查询的数据保证是唯一的,即由数据库约束(如主键)强制执行,那将是很好的选择。

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

    假设我的TableAcc

    AccountNumber - Primary Key, integer
    AccountName
    AccountOpenedDate
    AccountIsActive
    etc.
    

    我想查询 AccountNumber 987654 我用

    var data = datacontext.TableAcc.FirstOrDefault(obj => obj.AccountNumber == 987654);
    
        12
  •  -1
  •   El Dude    10 年前

    回答中遗漏了一件事……

    如果有多个结果,没有order by的first或default可以返回不同的结果,而服务器使用的索引策略正是基于这些结果。

    就我个人而言,我无法忍受在代码中看到first或efault,因为对我来说,它表示开发人员不关心结果。尽管它可以作为强制执行最新/最早版本的一种方式,但它还是有帮助的。我不得不纠正许多由使用first或default的粗心开发人员引起的问题。

        13
  •  -8
  •   Theron Govender    9 年前

    我不明白你为什么用 FirstOrDefault(x=> x.ID == key) 如果使用 Find(key) . 如果使用表的主键进行查询,则经验法则是始终使用 查找(密钥) . FirstOrDefault 应该用于谓词,比如 (x=> x.Username == username) 等。

    由于问题的标题不特定于DB上的LINQ或要列出的LINQ/IEnumerable等,因此不应投反对票。