IQuerable与IEnumable的区别

Posted hao_1234_1234

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IQuerable与IEnumable的区别相关的知识,希望对你有一定的参考价值。

 

核心区别:

IQueryable该接口会把查询表达式先缓存到表达式树Expression 中,只有当真正遍历发生的时候,才会由IQueryProvider解析表达式树,生成sql语句执行数据库查询操作。(离线集合)

IEnumable 该接口会立即返回需要的集合。(本地集合)

IQueryable接口(F12查看)

namespace System.Linq
{
    public interface IQueryable : IEnumerable
    {
        Type ElementType { get; }
        Expression Expression { get; }
        IQueryProvider Provider { get; }
    }
}

案例一:

先上代码

[csharp] view plain copy
 
  1. private void Form1_Load(object sender, EventArgs e)  
  2. {  
  3.     using (DemoContext context = new DemoContext())  
  4.     {  
  5.         var customer = context.cunstomer.Where(c => c.Name == "牡丹");  
  6.         foreach (var item in customer)  
  7.         {  
  8.             MessageBox.Show(item.Id.ToString());  
  9.         }  
  10.     }  
  11. }  

 

至于代码中的上下文定义以及实体集大家不必纠结,我们在这里要透过表象看本质。在上面的程序中添加断点,同时启动sql server profiler监视工具,运行程序。

技术分享图片

 

程序会在断点处停下来,如下所示

 

技术分享图片

 

上面只是到点断点处,当然断点处的语句还有执行,继续单步执行。

 

技术分享图片

 

执行过断点处所在的语句,观察监视工具还是什么都没有。

咦,是不是出什么问题了呢?为什么没有查询语句执行呢?真的是监视工具出问题了吗?

继续单步调试

 

技术分享图片

 

咦,这个时候怎么出现sql查询语句了。很奇怪吧,这就是ado.net EF的延迟加载技术,这里面很重要的一部分就是通过IQueryable接口实现的(具体我们放到最后再说)。

讲过了Queryable类的Where方法,接下来我们再来看一下Enumable类的Where方法。

修改上面的代码如下所示

 

[csharp] view plain copy
 
  1. private void Form1_Load(object sender, EventArgs e)  
  2. {  
  3.     using (DemoContext context = new DemoContext())  
  4.     {  
  5.         var customer = context.cunstomer.Where(c => c.Name == "牡丹").AsEnumerable();  
  6.         foreach (var item in customer)  
  7.         {  
  8.             MessageBox.Show(item.Id.ToString());  
  9.         }  
  10.     }  
  11. }  

技术分享图片

 

 

同样是打开监视工具,添加断点,运行程序

 

技术分享图片

 

单步调试,继续运行

 

技术分享图片

 

执行过断点所在的语句及执行了查询语句。

关于上面的两个测试总结如下。

 

(1)所有对于IEnumerable的过滤,排序等操作,都是在内存中发生的。也就是说数据已经从数据库中获取到了内存中,只是在内存中进行过滤和排序操作。

(2)所有对于IQueryable的过滤,排序等操作,只有在数据真正用到的时候才会到数据库中查询。这也是Linq的延迟加载核心所在。

 

案例二:

            //linq 表达式的返回值的类型是IQueryable
            IQueryable<HKSJ_USERS> temp = from u in dbContext.HKSJ_USERS
                       where u.ID > 4
                       select u;
            //初始化了一下IQueryable接口里面的三个参数作用:
            // 1 linq表达式转成表达式树Expression
            // 2 给元素类型 Type ElementType赋值,这里指的是<HKSJ_USERS>
            // 3 给提供者IQueryProvider Provider赋值,这里是efProvider,若是XML那就是xmlProvider,若是string 就stringProvider
         所以理论上linq可以无限扩展。
//当用到 IQueryable接口的集合的数据的时候,provider解析Expression然后获取相应的数据。进行遍历执行。 //linq to ef:查询是在数据库端进行过滤。 foreach (var hksjUsers in temp) { Console.WriteLine(hksjUsers.ID + " " + hksjUsers.UserName); } //IEnumable内存里面过滤:把数据库中的所有的数据都查询到程序里面来之后,再进行过滤。 //linq to object var demoList = from u in dbContext.HKSJ_USERS.AsIEnumable() //ToList() where u.ID > 4 select u; foreach (var hksjUsers in demoList) { }
       
         //List集合、Arrary,Dictionary,....都继承与IEnumable接口。

 

 

 

IEnumerable接口(F12查看)

namespace System.Collections
{
    //
    // 摘要:
    //     Exposes an enumerator, which supports a simple iteration over a non-generic collection.To
    //     browse the .NET Framework source code for this type, see the Reference Source.
    [ComVisible(true)]
    [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
    public interface IEnumerable
    {
        //
        // 摘要:
        //     Returns an enumerator that iterates through a collection.
        //
        // 返回结果:
        //     An System.Collections.IEnumerator object that can be used to iterate through
        //     the collection.
        [DispId(-4)]
        IEnumerator GetEnumerator();
    }
}

 

namespace System.Collections
{
    //
    // 摘要:
    //     Supports a simple iteration over a non-generic collection.
    [ComVisible(true)]
    [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
    public interface IEnumerator
    {
        //
        // 摘要:
        //     Gets the current element in the collection.
        //
        // 返回结果:
        //     The current element in the collection.
        object Current { get; }

        //
        // 摘要:
        //     Advances the enumerator to the next element of the collection.
        //
        // 返回结果:
        //     true if the enumerator was successfully advanced to the next element; false if
        //     the enumerator has passed the end of the collection.
        //
        // 异常:
        //   T:System.InvalidOperationException:
        //     The collection was modified after the enumerator was created.
        bool MoveNext();
        //
        // 摘要:
        //     Sets the enumerator to its initial position, which is before the first element
        //     in the collection.
        //
        // 异常:
        //   T:System.InvalidOperationException:
        //     The collection was modified after the enumerator was created.
        void Reset();
    }
}

 

参考:

https://blog.csdn.net/ydm19891101/article/details/50969323

 





以上是关于IQuerable与IEnumable的区别的主要内容,如果未能解决你的问题,请参考以下文章

IQueryableIEnumberable IList与List区别

IEnumable和yield

csharp IQuerable ToSqlString扩展方法。来自https://www.stevefenton.co.uk/2015/07/getting-the-sql-query-from-

python is 与==区别

EF急切加载和延迟加载的区别?

PHP中exit()与die()的区别