简体   繁体   English

当对象是IQueryable时返回IEnumerable

[英]Returning IEnumerable when the object is an IQueryable

I'm a bit confused about IEnumerable and IQueryable and interswapping of usages with Entity Framework. 我对IEnumerable和IQueryable以及实体框架的用法相互混淆感到有些困惑。 I've tried to do as much googling as I can on the subject but it hasn't seemed to help. 我已尝试在该主题上进行尽可能多的谷歌搜索,但似乎没有帮助。 So here's my situation. 这就是我的情况。

I have a function( MyClass is an EntityObject ): 我有一个函数( MyClass是一个EntityObject ):

IEnumerable<MyClass> GetMyClasses(int id) {
    return GetQuery().Where(p => p.Id==id);
}

IQueryable<MyClass> GetQuery() {
    // returns an IQueryable list here
}

Now my question is. 现在我的问题是。 Given I'm returning an IEnumerable here rather than an IQueryable , when the statement is executed with a ToList() will the underlying SQL generated take into account the Id == id statement and so only return filter items or will it bring all the objects of the database into memory and perform the Where clause on that list? 给定我在这里返回IEnumerable而不是IQueryable ,当使用ToList()执行该语句时,生成的基础SQL将考虑Id == id语句,因此仅返回过滤器项,否则它将带来所有对象将数据库存储到内存中并在该列表上执行Where子句?

Any helps, or even pointers to resources that describe this? 有什么帮助,甚至指向描述此内容的资源的指针吗?

when the statement is executed with a ToList() will the underlying SQL generated take into account the Id == id statement and so only return filter items 当使用ToList()执行该语句时,生成的基础SQL将考虑Id == id语句,因此仅返回过滤项

The short answer is 'Yes'. 简短的回答是“是”。

There is only Enumerable.ToList<T>(this IEnumumerable<T> e) and no counterpart for IQueryable<T> 仅存在Enumerable.ToList<T>(this IEnumumerable<T> e) ,而IQueryable<T>没有对应项

Everything inside GetMyClasses method will be operated as IQueryable<T> , but the restrictions added after will be in-memory. 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(); 
}

Methods ToList and Where is works like following 方法ToListWhere is如下所示

//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)));
}

The GetEnumerator method of IQueryable does query materialization. IQueryable的GetEnumerator方法会查询实现。

You're making this too complicated. 您使这个变得太复杂了。 Consider the following: 考虑以下:

public class Base { }

public class Derived : Base { }

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

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

You're wondering about the characteristics of the return value from Method . 您想知道Method的返回值的特征。 It will be an instance of Derived , but you will only be able to use it as a Base unless you cast it to Derived . 它将是Derived一个实例,但是除非将其DerivedDerived否则您将只能将其用作Base

So, your GetMyClasses will be returning an IQueryable<MyClass> that will be usable only as an IEnumerable<MyClass> . 因此,您的GetMyClasses将返回一个IQueryable<MyClass> ,该查询只能用作IEnumerable<MyClass>

This article is helpful: IQueryable vs IEnumerable in LINQ-to-SQL . 本文很有帮助: LINQ-to-SQL中的IQueryable与IEnumerable

Quoting that article, 'As per the MSDN documentation, calls made on IQueryable operate by building up the internal expression tree instead. 引用该文章,“根据MSDN文档,对IQueryable的调用是通过构建内部表达式树来进行的。 "These methods that extend IQueryable(Of T) do not perform any querying directly. Instead, their functionality is to build an Expression object, which is an expression tree that represents the cumulative query. "' “这些扩展IQueryable(Of T)的方法不会直接执行任何查询。相反,它们的功能是构建一个Expression对象,该对象是表示累积查询的表达式树。”

Expression trees are a very important construct in C# and on the .NET platform. 表达式树是C#和.NET平台上非常重要的构造。 (They are important in general, but C# makes them very useful.) To better understand the difference, I recommend reading about the differences between expressions and statements in the official C# 5.0 specification here. (它们通常很重要,但是C#使它们非常有用。)为了更好地理解它们之间的区别,建议您在此处阅读正式C#5.0规范中 表达式语句之间的区别 For advanced theoretical concepts that branch into lambda calculus, expressions enable support for methods as first-class objects. 对于分支到lambda演算的高级理论概念,表达式使对方法的支持成为一流的对象。 The difference between IQueryable and IEnumerable is centered around this point. IQueryable和IEnumerable之间的差异围绕这一点。 IQueryable builds expression trees whereas IEnumerable does not, at least not in general terms for those of us who don't work in the secret labs of Microsoft. IQueryable可以构建表达式树,而IEnumerable则不能,至少对于那些不在Microsoft秘密实验室工作的人而言,至少不是一般而言。

Here is another very useful article that details the differences from a push vs. pull perspective. 这是另一篇非常有用的文章,从推与拉角度详细介绍了差异。 (By "push" vs. "pull," I am referring to direction of data flow. Reactive Programming Techniques for .NET and C# (通过“推”与“拉”,我指的是数据流的方向。.NET和C#的响应式编程技术

Here is a very good article that details the differences between statement lambdas and expression lambdas and discusses the concepts of expression tress in greater depth: Revisiting C# delegates, expression trees, and lambda statements vs. lambda expressions. 这是一篇非常不错的文章,详细介绍了语句lambda和表达式lambda之间的区别,并更深入地讨论了表达式tress的概念: 复习C#委托,表达式树,lambda语句与lambda表达式。 .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM