在C#中,有两组扩展方法(例如Where)在IEnumerable和IQueryable之上起作用。其中哪些用于操作内存中的对象,哪些用于处理数据库。请帮助
[IEnumerable<T>.Where
方法扩展。它接受Func<TSource, bool> predicate
参数,强制在内存中进行过滤。从数据库查询数据时,IEnumerable
在服务器端执行select query
,在客户端将数据加载到内存中,然后过滤数据。对于IEnumerable<T>
情况,它将是LINQ-to-object
,这意味着与原始查询匹配的所有对象都必须从数据库加载到内存中。IEnumerable
适用于从内存集合中查询数据,如列表,数组等。
[IQueryable<T>.Where
方法扩展,它接受Expression<Func<TSource, bool>> predicate
参数。请注意,这是一个表达式,而不是委托,这使它可以将where条件转换为数据库条件。从数据库查询数据时,IQueryable
在服务器端使用所有过滤器执行select query
。区别在于IQueryable<T>
是允许LINQ-to-SQL(实际上是LINQ-to-anything)运行的接口。因此,如果您进一步优化对IQueryable<T>
的查询,则该查询将在数据库中执行(如果可能)。IQueryable
适用于查询内存不足(例如远程数据库,服务)集合中的数据。
IEnumerable<T>
公开枚举器,它支持对指定类型的集合进行简单的迭代。因此它用于内存中的对象
IEnumerable<T>
提供了针对已知数据类型的特定数据源评估查询的功能。因此是用于数据库
Reza Jenabi的回答说最重要的部分。
我只想补充一点,有时它在代码上非常相似,并且该错误可能需要一些时间才能注意到。如果您编写类似::>的方法
IQueryable<T>
您是“过滤器”,不会转换为SQL。 Things表的所有内容都将被加载到内存中,然后仅应用已加载数据的过滤器。在几乎是空的表上并不明显,但是在具有数千条记录的表上却非常昂贵。
因此,当您希望在SQL Server端执行IQueryable<T>
时请务必始终使用public List<Thing> GetList(Func<Thing, bool> filter)
{
return dbContext.Things.Where(filter).ToList();
}
:>
Expression<Func>
知道这两种方法将完全相同地被调用,例如:
public List<Thing> GetList(Expression<Func<Thing, bool>> filter) { return dbContext.Things.Where(filter).ToList(); }