LINQ Single vs First

问题描述 投票:199回答:11

LINQ:

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

有区别吗?

.net linq
11个回答
293
投票

If you're expecting a Single record, it's always good to be explicit in your code.

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

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

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

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
投票

很多我认识的人都使用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.

65
投票

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

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


25
投票

单()

返回查询的单个特定元素

使用时:如果恰好有1个元素;不是0或大于1.如果列表为空或具有多个元素,它将抛出异常“序列包含多个元素”

的SingleOrDefault()

返回查询的单个特定元素,如果未找到结果,则返回默认值

使用时:预期为0或1个元素时。如果列表包含2个或更多项,它将抛出异常。

第一()

返回具有多个结果的查询的第一个元素。

使用时:当需要一个或多个元素时,您只需要第一个元素。如果列表不包含任何元素,它将抛出异常。

FirstOrDefault()

返回包含任意数量元素的列表的第一个元素,如果列表为空,则返回默认值。

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


17
投票

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

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

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

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


15
投票

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

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

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


14
投票

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

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


7
投票

关于性能:一位同事和我正在讨论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在我的测试中总是稍微快一些。


5
投票

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


5
投票

您可以尝试简单的示例来获得差异。第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);
© www.soinside.com 2019 - 2024. All rights reserved.