LINQ:
当我确定查询将返回单个记录时,使用Single()
运算符是否更有效?First()
有区别吗?
LINQ:
当我确定查询将返回单个记录时,使用Single()
运算符是否更有效?First()
有区别吗?
Answers:
我知道其他人已经写了为什么您使用其中一个的理由,但是我想我想说明为什么当您指的是另一个时不应该使用其中一个。
注意:在我的代码中,我通常会使用FirstOrDefault()
,SingleOrDefault()
但这是一个不同的问题。
举个例子来说,该存储表Customers
使用不同语言的组合键(ID
,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();
它将返回一个对象,并且由于您正在使用排序,因此它将是返回的最新记录。
使用Single()
时感觉它应该明确,始终返回1条记录将有助于你避免逻辑错误。
customers.Where(predicate).Single()
customers.Single(predicate)
吗?
如果发现多个符合条件的记录,则Single将引发异常。First将始终从列表中选择第一条记录。如果查询仅返回1条记录,则可以使用First()
。
InvalidOperationException
如果集合为空,则两者都将引发异常。或者,您可以使用SingleOrDefault()
。如果列表为空,则不会抛出异常
单()
返回查询的单个特定元素
使用时:如果期望精确地为1个元素,则为0。不为0或大于1。如果列表为空或具有多个元素,则将引发异常“序列包含多个元素”
SingleOrDefault()
返回查询的单个特定元素,如果找不到结果,则返回默认值
当使用时:当期望0或1个元素时。如果列表包含2个或更多项,则将引发异常。
第一()
返回具有多个结果的查询的第一个元素。
当使用时:当期望1个或多个元素并且您只想要第一个时。如果列表不包含任何元素,它将引发异常。
FirstOrDefault()
返回具有任意数量元素的列表的第一个元素,如果列表为空,则返回默认值。
当使用时:当需要多个元素并且只需要第一个元素时。或列表为空,并且您想要指定类型的默认值,与相同
default(MyObjectType)
。例如:如果列表类型是list<int>
,它将返回列表的第一个数字;如果列表为空,则返回0。如果为list<string>
,它将返回列表中的第一个字符串;如果列表为空,则返回null。
First
时,预计1个以上的元素,不仅是“超过1”,并FirstOrDefault
与元素的任何量。
如果我还记得,Single()检查第一个元素之后是否还有另一个元素(如果是,则抛出异常),而First()在获取它之后停止。如果序列为空,则两者都引发异常。
就个人而言,我总是使用First()。
关于性能:我和一位同事正在讨论Single与First(或SingleOrDefault与FirstOrDefault)的性能,我在争辩说First(或FirstOrDefault)会更快并提高性能(我的全部目的是制作应用程序)跑得更快)。
我已经阅读了有关Stack Overflow的几篇文章,对此进行了辩论。有人说使用First而不是Single可以带来较小的性能提升。这是因为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)
我在'Foreign'关键字段上尝试了类似的查询,但没有索引的想法会证明First更快,但是Single在我的测试中总是稍快。
您可以尝试简单的示例以获取差异。第三行将引发异常;
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);
员工实体中的记录:
Employeeid = 1
:只有一名具有此ID的员工
Firstname = Robert
:不止一位具有此名称的员工
Employeeid = 10
:没有具有此ID的员工
现在有必要了解Single()
和First()
详细的意思。
单()
Single()用于返回表中唯一存在的一条记录,因此下面的查询将返回Employee,employeed =1
因为我们只有一个Employee,其Employeed
值为1。如果我们有两个记录,EmployeeId = 1
则会抛出错误(请参见下面的错误在第二个查询中,其中我们使用的示例Firstname
。
Employee.Single(e => e.Employeeid == 1)
上面将返回一个记录,其中包含1 employeeId
Employee.Single(e => e.Firstname == "Robert")
上面将引发异常,因为的表中有多个记录FirstName='Robert'
。例外是
InvalidOperationException:序列包含多个元素
Employee.Single(e => e.Employeeid == 10)
这将再次引发异常,因为不存在id = 10的记录。例外是
InvalidOperationException:序列不包含任何元素。
因为EmployeeId = 10
它将返回null,但是在我们使用Single()
它时将引发错误。为了处理空错误,我们应该使用SingleOrDefault()
。
第一()
First()从多个记录返回相应的记录,这些记录按照升序排序,birthdate
因此它将返回最早的'Robert'。
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Firstname == "Robert")
上面应该返回最早的一个,按照DOB的Robert。
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Employeeid == 10)
上面将抛出异常,因为不存在id = 10的记录。为了避免null异常,我们应该使用FirstOrDefault()
而不是First()
。
注意:当我们绝对确定它不能返回空值时,我们只能使用First()
/ Single()
。
在这两个函数中,都使用SingleOrDefault()或FirstOrDefault()来处理null异常,如果找不到记录,它将返回null。