当对象是IQueryable时返回IEnumerable

时间:2013-03-22 00:49:13

标签: c# entity-framework ienumerable iqueryable

我对IEnumerable和IQueryable以及与实体框架的使用交流感到有些困惑。我试图在这个主题上做尽可能多的谷歌搜索,但它似乎没有帮助。所以这就是我的情况。

我有一个功能(MyClassEntityObject):

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子句?

有任何帮助,甚至指向描述此资源的资源吗?

3 个答案:

答案 0 :(得分:1)

  

当使用 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(); 
}

方法ToListWhere的作用类似于

//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方法会查询实现。

答案 1 :(得分:1)

你这太复杂了。请考虑以下事项:

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>仅可用作{{1}}。

答案 2 :(得分:1)

这篇文章很有帮助: IQueryable vs IEnumerable in LINQ-to-SQL

引用该文章,&#39;根据MSDN文档,对IQueryable进行的调用通过构建内部表达式树来进行操作。 &#34;这些扩展IQueryable(Of T)的方法不直接执行任何查询。相反,它们的功能是构建一个Expression对象,它是一个表示累积查询的表达式树。 &#34;&#39;

表达式树是C#和.NET平台上非常重要的构造。 (它们一般很重要,但C#使它们非常有用。)为了更好地理解差异,我建议阅读表达式语句之间的差异 in the official C# 5.0 specification here.对于分支为lambda演算的高级理论概念,表达式支持将方法作为第一类对象。 IQueryable和IEnumerable之间的区别在于这一点。 IQueryable构建了表达式树,而IEnumerable则没有,至少对我们这些不在微软秘密实验室工作的人来说是一般性的。

这是另一篇非常有用的文章,详细介绍了推送与拉动视角的差异。 (通过&#34; push&#34; vs.&#34; pull,&#34;我指的是数据流的方向。Reactive Programming Techniques for .NET and C#

这是一篇非常好的文章,详细介绍了语句lambdas和表达式lambdas之间的区别,并更深入地讨论了表达式tress的概念:Revisiting C# delegates, expression trees, and lambda statements vs. lambda expressions.