2024-11-09 05:00:06

LINQ单对第一

LINQ:

当我确定查询将返回一条记录时,使用Single()操作符比First()更有效吗?

有区别吗?


当前回答

如果你期望一个单一的记录,在你的代码中显式总是好的。

我知道其他人已经写了为什么你要使用其中一个或另一个,但我认为我应该说明为什么你不应该使用一个,当你指的是另一个。

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

以一个表为例,它使用一个组合键(ID, Lang)存储不同语言的客户:

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

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

由于您的意图是返回一个单一客户使用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条记录时,使用它将帮助您避免逻辑错误。

其他回答

如果发现匹配条件的记录超过一条,Single将抛出异常。 First将始终从列表中选择第一条记录。如果查询只返回一条记录,您可以使用First()。

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

你可以尝试简单的例子来得到不同。 异常将在第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);

关于性能:我和一个同事正在讨论Single vs First(或SingleOrDefault vs FirstOrDefault)的性能,我认为First(或FirstOrDefault)会更快并提高性能(我都是关于让我们的应用程序运行得更快)。

I’ve read several posts on Stack Overflow that debate this. Some say there are small performance gains using First instead of Single. This is because First would simply return the first item while Single must scan all the results to make sure there isn’t a duplicate (ie: if it found the item in the first row of the table, it still would scan every other row to make sure there isn’t a second value matching the condition which would then throw an error). I felt like I was on solid ground with “First” being faster than “Single” so I set out to prove it and put the debate to rest.

我在我的数据库中设置了一个测试,并添加了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)

我在“外”键字段上尝试了类似的查询,没有索引,认为这将证明第一是更快的,但在我的测试中,单一总是略快。

如果我回忆,Single()检查在第一个元素之后是否有另一个元素(如果是这样,则抛出异常),而first()在得到它之后停止。如果序列为空,两者都会抛出异常。

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

他们是不同的。它们都断言结果集不是空的,但single也断言结果集不超过1个。我个人在只希望有1个结果的情况下使用Single,因为返回超过1个结果是一个错误,可能应该这样对待。