简体   繁体   English

.ToList()。First()和.Single之间的优点对于c#中的IQueryable

[英]Benefits between .ToList().First() verse .Single for IQueryable in c#

So I am running a linq query on a NOSQL database that should return only a single object if one exists with that Id or nothing if nothing exists, but it is possible there are two objects with the same id in the database (if someone else messed up.) Currently I have it implemented as follows: 因此,我在NOSQL数据库上运行linq查询,如果一个带有该ID的对象仅返回一个对象,否则不返回任何对象,但是数据库中可能有两个具有相同ID的对象(如果其他人弄乱了向上。)目前,我已将其实施如下:

(from c in [IQueryableThing] where c.Id.Equals(id)).ToList().First()

I have also considered the alternative 我也考虑过替代

(from c in [IQueryableThing] where c.Id.Equals(id)).Single()

I assume .Single() is faster but I am concerned that neither of these handles the case that there is no object with the correct id in the database. 我假设.Single()速度更快,但是我担心这些都无​​法处理数据库中没有具有正确ID的对象的情况。 I don't care if there is more than one returned. 我不在乎是否返回多个。 I only want one of them. 我只想要其中之一。 Eventually I will implement something to return the most recently modified. 最终,我将实现一些东西以返回最近修改的东西。

Basically my question is what is the best way to solve this problem of converting a queryable to a single instance in a way that handles the cases where there is no object with the correct id and there is more than one object with the correct id. 基本上,我的问题是解决此问题的最佳方法是什么,该方式将可查询的对象转换为单个实例,该方法可以处理没有正确ID的对象而有多个ID正确的对象的情况。

It sounds like you just want to call FirstOrDefault() , which does exactly what the name implies. 听起来您只想调用FirstOrDefault() ,其功能FirstOrDefault()其名。
Default means null . Default表示null

You should not call ToList() ; 你不应该调用ToList() ; that will needlessly download all of the results from the database. 这将不必要地从数据库中下载所有结果。

Using IQueryable.Single is more efficient: 使用IQueryable.Single效率更高:

  • Calling ToList enumerates the entire result set and stores each item in an single, contiguous array in memory. 调用ToList枚举整个结果集,并将每个项目存储在内存中的单个连续数组中。 The First then just takes the first item from the array. 然后, First只会从数组中获取第一项。
  • Calling IQueryable.Single evaluates only the first item in the list, and if no items are returned, throws an exception. 调用IQueryable.Single仅评估列表中的第一项,如果没有返回任何项,则引发异常。 It then checks to see if there are any more items in the result set, and throws an exception if there are any. 然后,它检查结果集中是否还有其他项目,如果有则抛出异常。

If you'd like to handle the case where no items exist in the set which match your criteria, but don't care if there are more than one, I'd strongly recommend using FirstOrDefault instead: 如果您想处理集合中不存在符合您条件的项目但又不在乎是否有多个项目的情况,我强烈建议您改用FirstOrDefault

var result = (from c in [IQueryableThing] where c.Id.Equals(id)).FirstOrDefault();
if (result == null)
{
    // no items found
}

This will translate to a TOP 1 in SQL, and simply return the first item in the result set, or if the result set is empty, it will simply return null (or the default value if you're dealing with structs). 这将转换为SQL的TOP 1 ,并仅返回结果集中的第一项,或者如果结果集为空,则将仅返回null (如果您正在处理结构,则返回默认值)。

The .ToList() shouldn't make a difference, it will just enumerate the queryable into an in-memory list. .ToList()不会有所作为,它只会将可查询对象枚举到内存列表中。 For your situation, you have a number of options. 对于您的情况,您有很多选择。 The two you've shown behave very differently: 您所显示的两种行为非常不同:

  • .First() - This will return the first element in the enumeration, or throw an exception if there are none. .First() -这将返回枚举中的第一个元素,如果不存在则抛出异常。
  • .Single() - This will return the only element in the enumeration, or throw an exception if there are none or if there are more than one. .Single() -这将返回枚举中的唯一元素,如果不存在不止一个,则抛出异常。
  • .FirstOrDefault() - This will return the first element in the enumeration, or a default value (which is null for reference types) if there are none. .FirstOrDefault() -这将返回枚举中的第一个元素,如果没有,则返回默认值(对于引用类型为null )。
  • .SingleOrDefault() - This will return the only element in the enumeration, or a default value (which is null for reference types) if there are none, or throw an exception if there are more than one. .SingleOrDefault() -这将在枚举,或一个默认值(这是返回的唯一元件null引用类型),如果没有, 抛出异常,如果有多于一个的。

It sounds like you want to use .FirstOrDefault() . 听起来您想使用.FirstOrDefault() Check if the result is null . 检查结果是否为null If it is, there were no matching elements. 如果是,则没有匹配元素。 If it isn't, you have the first matching element. 如果不是,则具有第一个匹配元素。

I believe you are looking for Enumerable.FirstOrDefault 我相信您正在寻找Enumerable.FirstOrDefault

Returns the first element of a sequence, or a default value if the sequence contains no elements. 返回序列的第一个元素,如果序列不包含任何元素,则返回默认值。

You should use .FirstOrDefault(c => c.ID.Equals(id)); 您应该使用.FirstOrDefault(c => c.ID.Equals(id));

It will return default if nothing is found (default is null for classes) or the first one it finds. 如果未找到任何内容(对于类,默认值为null )或找到的第一个内容,它将返回默认值。

In case you are sure that ONE and only ONE item exists and you will want to use Single() 如果您确定只有一个项目存在并且您将要使用Single()

If case you are not sure how many items will be returned used First() Or FirstOrDefault(). 如果遇到这种情况,则不确定使用First()还是FirstOrDefault()返回多少项目。

The difference is that Single() will throw an exception if more than one item exists. 不同之处在于,如果存在多个项,Single()将引发异常。 Very usefull if you want to trap insertion errors etc on a database without unique constraints. 如果您想在没有唯一约束的情况下在数据库中捕获插入错误等,则非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM