当对象是IQueryable时返回IEnumerable
本文关键字:返回 IEnumerable IQueryable 对象 | 更新日期: 2023-09-27 18:05:18
我对IEnumerable和IQueryable
以及与实体框架的用法互换有点困惑。我试着在谷歌上尽可能多地搜索这个主题,但似乎没有帮助。这就是我的情况。
我有一个函数(MyClass
是EntityObject
):
IEnumerable<MyClass> GetMyClasses(int id) {
return GetQuery().Where(p => p.Id==id);
}
IQueryable<MyClass> GetQuery() {
// returns an IQueryable list here
}
我的问题是。假设我在这里返回一个IEnumerable而不是IQueryable
,当语句用ToList()执行时,生成的底层SQL是否会考虑到Id == id
语句,因此只返回过滤器项,或者它会将数据库的所有对象带入内存并在该列表上执行Where子句?
有任何帮助,甚至指向描述这一点的资源吗?
当使用ToList()执行语句时,生成的底层SQL是否会考虑Id == Id语句,因此只返回过滤器项
简短的回答是"是"。
只有Enumerable.ToList<T>(this IEnumumerable<T> e)
,没有对应的IQueryable<T>
GetMyClasses
方法中的所有内容都将作为IQueryable<T>
操作,但之后添加的限制将在内存中。
IEnumerable<MyClass> GetMyClasses(int id) {
return GetQuery().Where(p => p.Id==id); // this always will work as IQueryable and handled by provider (in case of EF - the DB query will be performed)
}
IEnumerable<MyClass> MoreRestrictions(int id) {
return GetMyClasses(id)
.ToList(); // result list will be filtered by Id
}
IEnumerable<MyClass> MoreRestrictions(int id) {
return GetMyClasses(id)
.Where(x=>x.IsActive) // this where will be performed in memory on results filtered by Id.
.ToList();
}
方法ToList
和Where
的工作原理如下
//There is only one implementation of ToList()
public List<T> ToList<T>(this IEnumerable<T> e)
{
var list = new List<T>();
var enumerator = e.GetEnumerator();
while (enumerator.MoveNext())
{
var item = e.Current;
list.Add(item);
}
return list;
}
//Implementation for IEnumerable
public IEnumerable<T> Where<T>(this IEnumerable<T> e, Predicate predicate)
{
var enumerator = e.GetEnumerator();
while (enumerator.MoveNext())
{
var item = e.Current;
if (predicate(item))
yield return item;
}
}
//Implementation for IQueryable
public IQueryable<T> Where<T>(this IQueryable<T> e, Expression<Predicate> predicate)
{
MethodBase method = ...; // create generic method of Queryable.Where()
return e.Provider
.CreateQuery<T>(Expression.Call(null, method, e.Expression, Expression.Quote(predicate)));
}
IQueryable的GetEnumerator
方法实现查询物化
你把事情弄得太复杂了。考虑以下内容:
public class Base { }
public class Derived : Base { }
public Base Method() {
return GetOtherMethod();
}
public Derived GetOtherMethod()
{
return new Derived ();
}
您想知道Method
返回值的特征。它将是Derived
的一个实例,但是你只能将它作为Base
使用,除非你将它强制转换为Derived
。
因此,您的GetMyClasses
将返回IQueryable<MyClass>
,这将只能作为IEnumerable<MyClass>
使用。
这篇文章很有帮助:LINQ-to-SQL中的IQueryable vs IEnumerable .
引用那篇文章,"根据MSDN文档,对IQueryable的调用通过构建内部表达式树来操作。这些扩展了IQueryable(Of T)的方法不直接执行任何查询。相反,它们的功能是构建一个Expression对象,这是一个表示累积查询的表达式树。"'
表达式树是c#和。net平台上非常重要的结构。(它们通常很重要,但c#使它们非常有用。)为了更好地理解它们之间的区别,我建议阅读官方c# 5.0规范中表达式和语句之间的区别。对于扩展到lambda演算的高级理论概念,表达式支持将方法作为一级对象。IQueryable和IEnumerable的区别就在这一点上。IQueryable可以构建表达式树,而IEnumerable不能,至少对于我们这些不在微软秘密实验室工作的人来说是这样。
这是另一篇非常有用的文章,从推和拉的角度详细说明了差异。(通过"push"与"拉,"我指的是数据流的方向。.NET和c#响应式编程技术
这是一篇非常好的文章,详细介绍了语句lambda和表达式lambda之间的区别,并更深入地讨论了表达式压力的概念:重新审视c#委托、表达式树和lambda语句与lambda表达式…