首页 文章

LINQ Single vs First

提问于
浏览
198

LINQ:

当我确定查询将返回 a single record 时,使用 Single() 运算符而不是 First() 更有效吗?

有区别吗?

11 回答

  • 63

    如果您期望单条记录,那么在代码中明确表示总是好的 .

    我知道其他人已经写过为什么你使用其中一个,但我想我会说明为什么你不应该使用一个,当你另一个 .

    注意:在我的代码中,我通常会使用 FirstOrDefault()SingleOrDefault() ,但这是一个不同的问题 .

    例如,使用复合键( IDLang )以不同语言存储 Customers 的表:

    DBContext db = new DBContext();
    Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
    

    上面的代码引入了可能的逻辑错误(难以跟踪) . 它将返回多个记录(假设您有多种语言的客户记录),但它总是只返回第一个...有时可能有效......但不能返回其他语言 . 这是不可预测的 .

    既然你的意图是返回单 Customer 使用 Single() ;

    以下将抛出一个异常(在这种情况下你想要的):

    DBContext db = new DBContext();
    Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
    

    然后,你只需按下额头,然后对自己说......哎呀!我忘记了语言领域!以下是正确的版本:

    DBContext db = new DBContext();
    Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
    

    First() 在以下场景中很有用:

    DBContext db = new DBContext();
    NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
    

    它将返回一个对象,并且由于您正在使用排序,它将是返回的最新记录 .

    当你觉得它应该显式地总是返回1条记录时使用 Single() 将帮助你避免逻辑错误 .

  • 3

    如果找到符合条件的多条记录,则Single将抛出异常 . 首先将始终从列表中选择第一条记录 . 如果查询只返回1条记录,则可以使用 First() .

    如果集合为空,则两者都将抛出 InvalidOperationException 异常 . 或者,您可以使用 SingleOrDefault() . 如果列表为空,则不会抛出异常

  • 5

    Single()

    返回查询的单个特定元素使用时:如果预期恰好有1个元素;不是0或大于1.如果列表为空或具有多个元素,它将抛出异常“序列包含多个元素”

    SingleOrDefault()

    返回查询的单个特定元素,如果未找到结果,则返回默认值 . 使用时:当需要0或1个元素时 . 如果列表包含2个或更多项,它将抛出异常 .

    First()

    返回具有多个结果的查询的第一个元素 . 使用时:当需要一个或多个元素时,您只需要第一个元素 . 如果列表不包含任何元素,它将抛出异常 .

    FirstOrDefault()

    返回包含任意数量元素的列表的第一个元素,如果列表为空,则返回默认值 . 使用时:当预期有多个元素且您只想要第一个元素时 . 或者列表为空,您需要指定类型的默认值,与默认值(MyObjectType)相同 . 例如:如果列表类型为list <int>,它将返回列表中的第一个数字,如果列表为空,则返回0 . 如果是list <string>,它将从列表返回第一个字符串,如果列表为空,则返回null .

  • 7

    这两种方法之间存在细微的语义差异 .

    使用 Single 从应该包含一个元素但不再包含一个元素的序列中检索第一个(也是唯一的)元素 . 如果序列具有多于on元素,则调用 Single 将导致抛出异常,因为您指示应该只有一个元素 .

    使用 First 从可包含任意数量元素的序列中检索第一个元素 . 如果序列具有多于on元素,则调用 First 将不会导致抛出异常,因为您指示您只需要序列中的第一个元素而不关心是否存在更多元素 .

    如果序列不包含任何元素,则两个方法调用都将导致抛出异常,因为两个方法都期望至少存在一个元素 .

  • 290

    如果我记得,Single()检查第一个元素后面是否有另一个元素(如果是这种情况则抛出异常),而First()在获取后停止 . 如果序列为空,则两者都抛出异常 .

    个人而言,我总是使用First() .

  • 14

    如果您没有特别想要在有多个项目的情况下抛出异常, use First() .

    两者都很有效率,拿第一项 . First() 稍微提高效率,因为它不会检查是否有效还有第二项 .

    唯一的区别是 Single() 期望枚举中只有一个项目开始,并且如果有多个项目将抛出异常 . 如果您特别希望在这种情况下抛出异常,则使用 .Single() .

  • 4

    关于性能:一位同事和我正在讨论Single vs First(或SingleOrDefault vs FirstOrDefault)的性能,我正在争论First(或FirstOrDefault)会更快并提高性能(我只是为了制作我们的应用程序)跑得更快) .

    我已经阅读了有关Stack Overflow的几篇文章 . 有人说使用First而不是Single会有很小的性能提升 . 这是因为First只返回第一项,而Single必须扫描所有结果以确保没有重复(即:如果它在表的第一行中找到该项,它仍然会扫描每隔一行确保没有第二个值匹配条件然后会抛出错误) . 我觉得自己处于坚实的基础上,“第一”比“单身”更快,所以我开始证明这一点并让辩论得以休息 .

    我在我的数据库中设置了一个测试并添加了1,000,000行ID UniqueIdentifier外部UniqueIdentifier信息nvarchar(50)(填充了数字“0”到“999,9999”的字符串

    我加载了数据并将ID设置为主键字段 .

    使用LinqPad,我的目标是表明如果你使用Single搜索'Foreign'或'Info'的值,那将比使用First更糟糕 .

    我无法解释我得到的结果 . 几乎在所有情况下,使用Single或SingleOrDefault稍微快一些 . 这对我来说没有任何合理意义,但我想分享一下 .

    例如:我使用了以下查询:

    var q = TestTables.First(x=>x.Info == "314638") ;
    //Vs.
    Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)
    

    我在'外部'关键字段上尝试了类似的查询,这个字段没有被编入索引,认为First会更快,但Single在我的测试中总是稍微快一些 .

  • 17

    它们是不同的 . 它们都断言结果集不为空,但是单个也断言结果不超过1 . 我个人使用Single,我只希望得到1个结果,因为得到多于1个结果是一个错误,可能应该这样对待 .

  • 23

    您可以尝试简单的示例来获得差异 . 第3行会抛出异常;

    List<int> records = new List<int>{1,1,3,4,5,6};
            var record = records.First(x => x == 1);
            record = records.Single(x => x == 1);
    
  • 14

    我认识的很多人都使用FirstOrDefault(),但我更倾向于使用SingleOrDefault(),因为如果有多个数据不一致,通常会出现某种数据不一致 . 不过,这是在处理LINQ-to-Objects .

  • -1
    Lets below are the records in Employee entity
    
    Employeeid = 1: Only one employee with this ID 
    Firstname = Robert:   More than one employee with this name 
    Employeeid = 10: No employee   with this ID
    
    Now understand what Single() and First() in detail
    
    **Single()**
    Single() is use to return single record which exists only one in a table, so below query will return Employee whose employee id =1 because we have Employee is one whose Employee id is 1. If we have two records for EmployeeId = 1 then it give the error, kindly see error below in second query where  we are taking example of name. 
    Employee.Single(e => e.Employeeid == 1)
    Above will return single record, which have 1 employeeId
    
    Employee.Single(e => e.Firstname == "Robert")
    Above will give exception because multilple records are in table for FirstName='Robert' 
    And exception will be
    InvalidOperationException: Sequence contains more than one element
    
    Employee.Single(e => e.Employeeid == 10)
    Above again will throw exception because no record exists for id=10 and exception will be
    InvalidOperationException: Sequence contains no elements.
    For EmployeeId = 10 it will return null but we are using only Single() then it will give error to handle null error we should use SingleOrDefault().
    
    **First()**
    First() return from multiple same records according to order as we using ascending order on birthdate so it will return 'Rober' who is oldest.
    Employee.OrderBy(e => e. Birthdate)
    .First(e => e.Firstname == "Robert")
    Above should return the oldest one robert as per DOB
    
    
    Employee.OrderBy(e => e. Birthdate)
    .First(e => e.Employeeid == 10)
    Above will give the exception as no record for id =10 
    To avoid null exception we should use FirstOrDefault() not only First().
    
    Note: We can use only First()/Single() when we damn sure that it must going to return not null value.
    
    
    In both function **SingleOrDefault() OR FirstOrDefault()**
    It will handled null exception, in case of no record found it will give null.
    

相关问题