如何理解EntityFramework中的IQueryable和IQueryProvider接口

这篇文章主要介绍“如何理解Entity Framework中的IQueryable和IQueryProvider接口”,在日常操作中,相信很多人在如何理解Entity Framework中的IQueryable和IQueryProvider接口问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Entity Framework中的IQueryable和IQueryProvider接口”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

成都创新互联从2013年成立,是专业互联网技术服务公司,拥有项目成都网站设计、成都网站制作、外贸网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元金乡做网站,已为上家服务,为金乡各地企业和个人服务,联系电话:18980820575

 IQueryable接口

      我们先聊聊这个接口,因为我们在使用EF中经常看到linq to sql语句的返回类型是IQueryable,我们可以看下这个接口的结构:

复制代码代码如下:

public interface IQueryable : IEnumerable
{
      Type ElementType { get; }
      Expression Expression { get; }
      IQueryProvider Provider { get; }
}

      或许会有人很奇怪,当我们在开发过程中使用这个接口的时候,提供的方法远远不止这么点,因为微软提供了强大的Queryable类,当然大家不要以为这个类是实现IQueryable然后实现了很多方法,如果是那样那些第三方库怎么自定义呢?所以Queryable只是一个静态类,对IQueryable接口进行了扩展,下面是笔者在.Net Reflector截图中一部分:

如何理解Entity Framework中的IQueryable和IQueryProvider接口

       如果读者细心一点会发现linq to sql并不会导致实际的查询,只有当我们真正开始使用的时候才从数据库中开始查询数据。

IQueryProvider接口

      如果我们调试的EF的话,会看到生成的T-SQL语句。T-SQL就是根据表达式树分析从而得出的,而核心就是IQueryProvider接口,下面就是该接口的结构:

复制代码代码如下:


public interface IQueryProvider
{
        IQueryable CreateQuery(Expression expression);
        IQueryable CreateQuery(Expression expression);
        object Execute(Expression expression);
        TResult Execute(Expression expression);
}

      其中CreateQuery就是负责解析表达式树的,当然还要将处理后的结果返回,以便接着分析下面的语句,当然这中间只是分析,你完全可以根据表达式树得出你自己需要的查询语句,比如SQL或者其他什么,只有在真正使用数据的时候才会调用Execute方法,这个时候就可以根据我们自己分析的语句开始进行实际的查询了。

 实例分析

QueryProvider类

      光说不练我们永远不能明白其中的原理,所以下面我们就简单的举一个例子来展示下。首先我们先实现IQueryProvider接口,其中会用到一个Query类,这个类会在后面进行介绍,首先我们新建一个QueryProvider类实现IQueryProvider接口,首先我们看下CreateQuery方法:

如何理解Entity Framework中的IQueryable和IQueryProvider接口

 我们可以看到下面这句话:

如何理解Entity Framework中的IQueryable和IQueryProvider接口

实际的含义就是创建Query<>的实例,并且泛型参数是elementType,参数是thisexpression

 最后就是Execute方法了,传递一个Expression参数,并获取最后的结果,笔者在这里直接是写死的值:

如何理解Entity Framework中的IQueryable和IQueryProvider接口

 Query类

      仅仅只有QueryProvider还没用,我们还需要一个能够保存表达式树状态的类,当然也包括了我们解析表达式后的结果也可以保存在其中,这样我们在IQueryProvider的Execute方法中就可以根据我们解析的结果执行执行并返回结果了。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

       但是在后面的过程中Query中的Expression将是QueryProvider中的expression值。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

      OK,我们开始看看是如何分析这句LINQ语句的。

       首先我们看下在一开始执行时Query中Expression的返回值(如下图):

如何理解Entity Framework中的IQueryable和IQueryProvider接口

      我们看到里面的字符串是 Where(item => (item == 123)),通过这句话我们就可以明白其实LINQ中的where实质上就是利用Where方法,并传递给它对应的lambda表达式。分析完了where部分,下面就是FirstOrDefault部分了。

 分析FirstOrDefault

      当执行到FirstOrDefault的时候我们可以查看t的值,会发现t实际上就是QueryProvider中CreateQuery的返回值。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

      接着我们开始执行下面FirstOrDefault方法,发现会再一次的去获取Expression的值,而此时Expression的值就是上面CreateQuery传递给我们的参数expression

如何理解Entity Framework中的IQueryable和IQueryProvider接口

       至此一个简单的流程就结束了,最后就是返回笔者写死的123这个值了。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

       通过上面这个例子我们基本了解了其工作的流程,下面我们将一步一步的分析我们这个where item == 123,当然我们将会用到递归,所以请大家整理好自己的思路,一步一步的看如何从一个表达式树中分析这条语句。

 分析表达式树实战

      首先我们一个分析表达式树的方法,这个方法我们暂且放在QueryProvider中:

复制代码代码如下:


public void AnalysisExpression(Expression exp)
        {
            switch (exp.NodeType)
            {
                case ExpressionType.Call:
                    {
                        MethodCallExpression mce = exp as MethodCallExpression;
                        Console.WriteLine("The Method Is {0}", mce.Method.Name);
                        for (int i = 0; i < mce.Arguments.Count; i++)
                        {
                            AnalysisExpression(mce.Arguments[i]);
                        }
                    }
                    break;
                case ExpressionType.Quote:
                    {
                        UnaryExpression ue = exp as UnaryExpression;
                        AnalysisExpression(ue.Operand);
                    }
                    break;
                case ExpressionType.Lambda:
                    {
                        LambdaExpression le = exp as LambdaExpression;
                        AnalysisExpression(le.Body);
                    }
                    break;
                case ExpressionType.Equal:
                    {
                        BinaryExpression be = exp as BinaryExpression;
                        Console.WriteLine("The Method Is {0}", exp.NodeType.ToString());
                        AnalysisExpression(be.Left);
                        AnalysisExpression(be.Right);
                    }
                    break;
                case ExpressionType.Constant:
                    {
                        ConstantExpression ce = exp as ConstantExpression;
                        Console.WriteLine("The Value Type Is {0}", ce.Value.ToString());
                    }
                    break;
                case ExpressionType.Parameter:
                    {
                        ParameterExpression pe = exp as ParameterExpression;
                        Console.WriteLine("The Parameter Is {0}", pe.Name);
                    }
                    break;
                default:
                    {
                        Console.Write("UnKnow");
                    }
                    break;
            }
        }

并在CreateQuery中调用这个方法

如何理解Entity Framework中的IQueryable和IQueryProvider接口

      当然调用一个方法必须要有参数,所以下面还需要循环Arguments去分析具体的参数,其中也包括调用这个方法的对象,自然我们首先是分析调用这个方法的对象,这里我们进行了第一次的递归调用,跳到了ExpressionType.Constant。

 ExpressionType.Constant

      NodeType为这个类型,我们就可以通过ConstantExpression类型来获取对应的参数,通过Value我们可以可以获取到调用where方法的对象,当然到这里就不会继续往下分析了。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

 ExpressionType.Quote

      如果接触过lambda的人可能会认为类型应该是Lambda,但实际上不会直接跳转到那,而是先跳转到Quote,然后我们再把转换成UnaryExpression类型,然后再继续分析其中Operand属性,而这个属性的NodeType就是Lambda了。个人认为这个应该是区分lambda和普通的方法,因为where不仅仅可以接收lambda同时也可以是常规的方法,所以这里还需要这一层。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

 ExpressionType.Lambda

跳转到这,大家就不会感觉奇怪了,这里为了简洁。笔者并没有分析参数,而是直接分析Body部分,因为这部分才是我们的关键。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

       我当时还奇怪,怎么没有这个类型呢,最后才知道玩的是这一出。到此为止,我们继续分析这个相等操作的左右两边的参数吧。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

到这左边的参数分析完毕,我们开始分析右边的参数。

 ExpressionType.Constant

      我们可以轻松的想到对应的Value就是123了,到此整个表达式就分析完毕了。

如何理解Entity Framework中的IQueryable和IQueryProvider接口

到此,关于“如何理解Entity Framework中的IQueryable和IQueryProvider接口”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!


分享名称:如何理解EntityFramework中的IQueryable和IQueryProvider接口
文章位置:http://hbruida.cn/article/ggeced.html