深入理解IEnumerable和IQueryable两接口的区别
from:http://blog.csdn.net/ydm19891101/article/details/50969323
无论是在ado.net EF或者是在其他的Linq使用中,我们经常会碰到两个重要的静态类Enumerable、Queryable,他们在System.Linq命名空间下。那么这两个类是如何定义的,又是来做什么用的呢?特别是Queryable类,它和EF的延迟加载技术有什么联系呢?
好,带着上面的问题开始我们今天的学习。
首先介绍两个类的定义
(1)Enumerable类,对继承了IEnumerable<T>接口的集合进行扩展;
(2)Queryable类,针对继承了IQueryable<T>接口的集合进行扩展。
在继续学习之前,我们先来看一下EF中定义的实体集DbSet<T>
通过上面的截图我们可以看到 DbSet<T>实现了IQueryable<T>、IEnumerable<T>接口。
与上面的两句话结合起来意思就是可以通过两个静态类对DbSet<T>进行扩展操作。其实查看两个类的源码可以知道,这两个类对实现了IQueryable<T>、IEnumerable<T>接口的集合进行了很多方法的扩展。
可能你还不知道如何进行扩展方法的定义以及操作,没事儿,请参考另外一篇文章:C#扩展方法的理解
但是那么的扩展方法不都是我们需要的,我们在ado.net EF中最常用的就是扩展的Where方法。
两个类中Where扩展方法的定义分别如下
(1)Enumerable类
- public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
- public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
观察Where方法,可以看到第一个参数是实现了IEnumable接口的类,第二个参数是一个Func<T>委托类型
(2)Queryable类
- public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
- public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate);
观察Where方法,可以看到第一个参数是实现了IEnumable接口的类,第二个参数是一个Expresssion类型
很显然,两个类扩展的Where方法是不同的,那具体有什么不同呢?那么这种不同又导致什么结果呢?
OK,带着疑问继续往下学习。
为了便于大家好学习,在这里,我们编写一段代码,通过监视工具查看两者的区别。
先上代码
- private void Form1_Load(object sender, EventArgs e)
- {
- using (DemoContext context = new DemoContext())
- {
- var customer = context.cunstomer.Where(c => c.Name == "牡丹");
- foreach (var item in customer)
- {
- MessageBox.Show(item.Id.ToString());
- }
- }
- }
至于代码中的上下文定义以及实体集大家不必纠结,我们在这里要透过表象看本质。在上面的程序中添加断点,同时启动sql server profiler监视工具,运行程序。
程序会在断点处停下来,如下所示
上面只是到点断点处,当然断点处的语句还有执行,继续单步执行。
执行过断点处所在的语句,观察监视工具还是什么都没有。
咦,是不是出什么问题了呢?为什么没有查询语句执行呢?真的是监视工具出问题了吗?
继续单步调试
咦,这个时候怎么出现sql查询语句了。很奇怪吧,这就是ado.net EF的延迟加载技术,这里面很重要的一部分就是通过IQueryable接口实现的(具体我们放到最后再说)。
讲过了Queryable类的Where方法,接下来我们再来看一下Enumable类的Where方法。
修改上面的代码如下所示
- private void Form1_Load(object sender, EventArgs e)
- {
- using (DemoContext context = new DemoContext())
- {
- var customer = context.cunstomer.Where(c => c.Name == "牡丹").AsEnumerable();
- foreach (var item in customer)
- {
- MessageBox.Show(item.Id.ToString());
- }
- }
- }
同样是打开监视工具,添加断点,运行程序
单步调试,继续运行
执行过断点所在的语句及执行了查询语句。
关于上面的两个测试总结如下。
(1)所有对于IEnumerable的过滤,排序等操作,都是在内存中发生的。也就是说数据已经从数据库中获取到了内存中,只是在内存中进行过滤和排序操作。
(2)所有对于IQueryable的过滤,排序等操作,只有在数据真正用到的时候才会到数据库中查询。这也是Linq的延迟加载核心所在。
那最后一个问题,IQueryable接口为何那么特殊呢?
观察它的定义
- // 摘要:
- // 提供对未指定数据类型的特定数据源的查询进行计算的功能。
- public interface IQueryable : IEnumerable
- {
- // 摘要:
- // 获取在执行与 System.Linq.IQueryable 的此实例关联的表达式树时返回的元素的类型。
- //
- // 返回结果:
- // 一个 System.Type,表示在执行与之关联的表达式树时返回的元素的类型。
- Type ElementType { get; }
- //
- // 摘要:
- // 获取与 System.Linq.IQueryable 的实例关联的表达式树。
- //
- // 返回结果:
- // 与 System.Linq.IQueryable 的此实例关联的 System.Linq.Expressions.Expression。
- Expression Expression { get; }
- //
- // 摘要:
- // 获取与此数据源关联的查询提供程序。
- //
- // 返回结果:
- // 与此数据源关联的 System.Linq.IQueryProvider。
- IQueryProvider Provider { get; }
- }
该接口有三个特殊的属性,具体内容代码已经介绍了,那查询时具体又是如何执行呢?
答案是该接口会把查询表达式先缓存到表达式树中,只有当真正遍历发生的时候,才会由IQueryProvider解析表达式树,生成sql语句执行数据库查询操作。
哎呀,写到现在终于差不多快写完了。
上面介绍了两个接口的区别与联系,具体使用哪种就看自己的项目需求了。
最后补充一下List.Where()方法,还是以代码说明。
- List<string> fruits =
- new List<string> { "apple", "passionfruit", "banana", "mango",
- "orange", "blueberry", "grape", "strawberry" };
- IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);
- foreach (string fruit in query)
- {
- Console.WriteLine(fruit);
查看List<T>的定义,如下图所示
深入理解IEnumerable和IQueryable两接口的区别的更多相关文章
- 【C#夯实】我与接口二三事:IEnumerable、IQueryable 与 LINQ
序 学生时期,有过小组作业,当时分工一人做那么两三个页面,然而在前端差不多的时候,我和另一个同学发生了争执.当时用的是简单的三层架构(DLL.BLL.UI),我个人觉得各写各的吧,到时候合并,而他觉得 ...
- C# IEnumerable与IQueryable ,IEnumerable与IList ,LINQ理解Var和IEnumerable
原文:https://www.cnblogs.com/WinHEC/articles/understanding-var-and-ienumerable-with-linq.html 使用LINQ从数 ...
- IEnumerable 与 IQueryable
无论是在ado.net EF或者是在其他的Linq使用中,我们经常会碰到两个重要的静态类Enumerable.Queryable,他们在System.Linq命名空间下.那么这两个类是如何定义的,又是 ...
- IEnumerable和IQueryable和Linq的查询
IEnumerable和IEnumerable 1.IEnumerable查询必须在本地执行.并且执行查询前我们必须把所有的数据加载到本地.而且更多的时候.加载的数据有大量的数据是我们不需要的无效数据 ...
- IEnumerable和IQueryable区别、优缺点
转自 http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...
- EntityFramework IEnumerable,IQueryable ,Include
使用IQueryable using (var db = new CentaStaffEntities()) { IQueryable<Staff> queryablestaffs = d ...
- IEnumerable和IQueryable的区别
转自:http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...
- IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树
关于IEnumerable和IQueryable的区别,这事还要从泛型委托Func<T>说起.来看一个简单的泛型委托例子: class Program { static void Main ...
- IEnumerable 与 Iqueryable 的区别
IEnumerable 和 IQueryable 共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable<T> 的对象上运行,另一组在类型为 IQueryable&l ...
随机推荐
- mysql show profiles使用分析sql性能
mysql show profiles使用分析sql性能 Show profiles是5.0.37之后添加的,要想使用此功能,要确保版本在5.0.37之后. 查看一下我的数据库版本 mysql> ...
- asp.net权限控制的方式
我们在使用asp.net开发Web程序的时候经常需要进行一些权限控制,如: 限制用户没有登陆就无法查看一些页面,又或者是说登陆之后如果不是管理员,或是没有响应的权限就无法进行相关的操作. 实现的方法有 ...
- virtualBox安装centos7并配置nginx php mysql运行环境
virtualBox安装centos7并配置nginx php mysql运行环境 一:virtualBox安装centos7并进行基础设置 1.下载dvd.iso安装文件,下载地址:https:// ...
- Charles的HTTPS抓包方法及原理,下载安装ssl/https证书
转自:https://zhubangbang.com/charles-https-packet-capture-method-and-principle.html 本文的Charles,适应windo ...
- 被动信息收集1——DNS基础 + DNS解析工具 NSLOOKUP使用
被动信息收集 特点: 基于公开渠道 与目标不直接接触 避免留下一切痕迹 标准參考--OSINT: 美国军方 北大西洋公约组织 名词解释 DNS--Domain Name System 域名系统 因特网 ...
- 查看FC HBA卡信息的方法
在配置磁盘阵列或虚拟磁带库时,往往会以FC接口与主机对接,那么就涉及FC HBA卡的查看,本文就这个问题进行了总结与整理. 一.Windows 系统 在Windows系统中,可以使用FC HBA卡厂家 ...
- 基于Opencv自带BP网络的车标简易识别
代码地址如下:http://www.demodashi.com/demo/12966.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 1.准备工作 1.1 训练集和测 ...
- 网络协议系列之三:IP
前言 这篇博客主要对IP协议中一些基础知识点加以总结,并将书中一些晦涩难懂的部分去除了.IP地址协议是网络层中最重要的协议,IP地址协议能够对因特网上的全部设备进行唯一标识.也正由于有了IP协议,我们 ...
- IIS各种问题汇总
1.不能在此路径中使用此配置节.如果在父级别上锁定了该节,便会出现这种情况.锁定是默认设置的(overrideModeDefault="Deny"),或者是通过包含 overrid ...
- Android BlueDroid(三):BlueDroid蓝牙开启过程enable
关键词:bluedroid enableNative BTIF_TASK BTU_TASK bt_hc_work_thread set_power preload GKI作者:xubin3417 ...