LINQ单对第一
LINQ:
当我确定查询会返回单个logging时,使用Single()
运算符比First()
更有效吗?
有区别吗?
如果您期待Singlelogging,那么在代码中明确表示总是很好的。
我知道其他人已经写了你为什么使用其中一个,但我想我会说明为什么你不应该使用一个,当你的意思是另一个。
注意:在我的代码中,我通常会使用FirstOrDefault()
和SingleOrDefault()
但这是一个不同的问题。
例如,以一个使用复合键( ID
, Lang
)的不同语言存储Customers
的表格为例:
DBContext db = new DBContext(); Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
上面的代码引入了一个可能的逻辑错误(难以追踪)。 它会返回多个logging(假设你有多种语言的客户logging),但它总是只返回第一个logging……有时可能有效……但不是其他logging。 这是不可预测的。
由于您的意图是返回一个单一的Customer
使用Single()
;
以下将抛出一个exception(这是你在这种情况下):
DBContext db = new DBContext(); Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
然后,你只要打在自己的额头上,并对自己说… OOPS! 我忘了语言领域! 以下是正确的版本:
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();
它将返回一个对象,因为你正在使用sorting,它将是最近的logging被返回。
使用Single()
当你觉得它应该显式地总是返回1logging将帮助你避免逻辑错误。
如果find多个匹配条件的logging,Single将抛出exception。 首先将始终从列表中select第一条logging。 如果查询只返回1条logging,则可以使用First()
。
如果集合是空的,两者都会抛出一个InvalidOperationException
exception。 或者,您可以使用SingleOrDefault()
。 如果列表为空,这不会引发exception
这两种方法之间存在细微的语义差异。
使用Single
从一个应该包含一个元素的序列中检索第一个(也是唯一的)元素。 如果序列有多于on的元素,那么你调用Single
将导致一个exception被抛出,因为你指出应该只有一个元素。
使用First
可从包含任意数量元素的序列中检索第一个元素。 如果序列有多于on元素,那么First
的调用将不会引发exception,因为您表示只需要序列中的第一个元素,而不在乎是否存在更多元素。
如果序列不包含任何元素,那么这两个方法调用都会导致抛出exception,因为这两个方法至less需要一个元素。
如果我记得,Single()会检查第一个元素之后是否有另一个元素(如果是这种情况,则抛出exception),而First()在获取它之后停止。 如果序列为空,则都会抛出exception。
Personnally,我总是使用First()。
单()
返回查询的单个特定元素
使用时 :如果预计只有一个元素, 不是0或大于1.如果列表为空或有多个元素,则会抛出exception“序列包含多个元素”
的SingleOrDefault()
返回查询的单个特定元素,如果未find结果,则返回默认值
使用时 :预计有0或1个元素时。 如果列表中有2个或更多的项目,它将会抛出exception。
第一()
返回具有多个结果的查询的第一个元素。
使用时 :当预计有一个或多个元素时,只需要第一个元素。 如果列表中不包含任何元素,它将抛出一个exception。
FirstOrDefault()
返回任意数量元素的列表的第一个元素,如果列表为空,则返回一个默认值。
使用时 :预计有多个元素时,只需要第一个元素。 或者列表是空的,你想要一个指定types的默认值,和
default(MyObjectType)
。 例如:如果列表types是list<int>
,它将返回列表中的第一个数字,如果列表为空,则返回0。 如果是list<string>
,它将返回列表中的第一个string,如果列表为空,则返回null。
如果您不特别需要在有多个项目的情况下引发exception,请使用First()
。
两者都是高效的,拿第一个项目。 First()
稍微高效一点,因为它不会检查是否有第二个项目。
唯一的区别是Single()
期望在枚举中只有一个项目开始,如果有多个项目,将会抛出一个exception。 如果在这种情况下特别需要引发exception , 则 使用 .Single()
。
关于性能:我和一个同事正在讨论Single vs First(或SingleOrDefault vs FirstOrDefault)的性能,而且我争辩说First(或FirstOrDefault)会更快并且性能更好(我全部都是关于使我们的应用程序跑得更快)。
我已经阅读了Stack Overflow上的几篇关于这个问题的文章。 有人说使用First而不是Single可以获得很小的性能提升。 这是因为First会简单地返回第一个项目,而Single必须扫描所有结果以确保没有重复(即:如果在表格的第一行中find该项目,它仍然会扫描每一行到确保没有第二个值匹配的条件,然后会抛出一个错误)。 我觉得自己在“第一”比“单”快,所以我着手certificate这一点,让辩论rest。
我在我的数据库中设置了一个testing,并添加了1,000,000行ID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar(50)(填充数字string“0”到“999,9999”
我加载数据并将ID设置为主键字段。
使用LinqPad,我的目标是显示如果您使用Singlesearch“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在我的testing中总是稍微快一点。
他们是不同的。 他们都声称结果集不是空的,但是单个也声明结果不会超过1个。 我个人使用单一的情况下,我只希望有1结果只是因为得到超过1个结果是错误的,可能应该被视为这样的。
很多我认识的人使用FirstOrDefault(),但我更倾向于使用SingleOrDefault(),因为如果有多个数据通常会是某种数据不一致。 这是处理LINQ到对象,但。
你可以尝试一个简单的例子来获得差异。 第三行将抛出exception;
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);