我经常看到调用ToList会使查询每次都执行。我有点困惑。那么在这种情况下,第二次调用ToList会使查询多次执行吗?在什么情况下查询会多次执行?
//This gets from database and ToList is already called here
List<Customer> Customers = GetCustomersFromDataBase();
//ToList is called here again
List<Customer> FilteredCustomers = (from c in Customerswhere c.id == 1c).ToList();
修改
我刚刚提供了这个代码示例,以了解ToList的真正作用。我没有这样实现它。 此外,我进行存储过程调用以从db返回客户,并从返回的数据表中创建客户列表。
答案 0 :(得分:7)
在ToList
上拨打ToArray
(或AsEnumerable
,IQueryable
等)即可执行查询。之后,您使用的任何LINQ表达式都将在内存列表中运行。
例如,您的代码:
List<Customer> Customers = GetCustomersFromDataBase();
这将导致List
个Customer
个对象代表数据库记录。该列表现在独立于用于从数据库中获取结果的查询,但仍需要从数据库中提取Customer
对象中的链接记录。
然后当你这样做时:
List<Customer> FilteredCustomers = (from c in Customers where c.id == 1c).ToList();
这不是在数据库上运行,而是在从前一个语句返回的内存中的结果上运行。在这种情况下,您不会多次查询数据库。
影响效果的地方是指您有一个IQueryable
对象,您可以多次直接调用ToList
。在ToList
上对IQueryable
的每次调用都将导致对数据库的调用,所有伴随对象都会在后台跟踪。通常,这是您要避免的,尽管在枚举结果之前对查询进行额外过滤可能会导致更好的性能,如果查询选择的记录总数很大并且过滤器会拉取数据的小子集。
答案 1 :(得分:3)
在您的方案中,查询只执行一次。
下面:
List<Customer> FilteredCustomers = (from c in Customers where c.id == 1c).ToList();
此行仅基于变量Customers
进行过滤,该变量是由ToList()
填充的客户表的副本。
答案 2 :(得分:1)
检查Enumerable.ToList()的源代码(google for it) Enumerable.ToList()
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
return new List<TSource>(source);
}
所以是ToList()。ToList(),是一种浪费,一个新列表被创建,第一个ToList中的所有(引用)元素都被复制到第二个,导致新的内存要分配,第一个列表是垃圾回收,导致内存被释放。