0

我对 IEnumerable 以及IQueryable与 Entity Framework 的使用交换有点困惑。我已经尝试尽可能多地在这个主题上进行谷歌搜索,但它似乎没有帮助。所以这是我的情况。

我有一个函数(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 子句?

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

4

3 回答 3

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方法进行查询物化。

于 2013-03-22T00:58:23.083 回答
1

你把这弄得太复杂了。考虑以下:

public class Base { }

public class Derived : Base { }

public Base Method() {
    return GetOtherMethod();
}

public Derived GetOtherMethod()
{
    return new Derived ();
}

您想知道 from 的返回值的特征Method。它将是 的一个实例Derived,但您只能将其用作 a Base,除非您将其强制转换为Derived.

因此,您GetMyClasses将返回一个IQueryable<MyClass>只能用作IEnumerable<MyClass>.

于 2013-03-22T01:06:04.343 回答
1

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

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

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

这是另一篇非常有用的文章,详细介绍了推与拉的区别。(通过“推”与“拉”,我指的是数据流的方向。.NET 和 C# 的反应式编程技术

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

于 2014-03-14T02:17:50.110 回答