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类

  1. public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
  2. public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);

观察Where方法,可以看到第一个参数是实现了IEnumable接口的类,第二个参数是一个Func<T>委托类型

(2)Queryable类

  1. public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
  2. public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int, bool>> predicate);

观察Where方法,可以看到第一个参数是实现了IEnumable接口的类,第二个参数是一个Expresssion类型
很显然,两个类扩展的Where方法是不同的,那具体有什么不同呢?那么这种不同又导致什么结果呢?

OK,带着疑问继续往下学习。

为了便于大家好学习,在这里,我们编写一段代码,通过监视工具查看两者的区别。

先上代码

  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方法。

修改上面的代码如下所示

  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的延迟加载核心所在。

那最后一个问题,IQueryable接口为何那么特殊呢?

观察它的定义

  1. // 摘要:
  2. //     提供对未指定数据类型的特定数据源的查询进行计算的功能。
  3. public interface IQueryable : IEnumerable
  4. {
  5. // 摘要:
  6. //     获取在执行与 System.Linq.IQueryable 的此实例关联的表达式树时返回的元素的类型。
  7. //
  8. // 返回结果:
  9. //     一个 System.Type,表示在执行与之关联的表达式树时返回的元素的类型。
  10. Type ElementType { get; }
  11. //
  12. // 摘要:
  13. //     获取与 System.Linq.IQueryable 的实例关联的表达式树。
  14. //
  15. // 返回结果:
  16. //     与 System.Linq.IQueryable 的此实例关联的 System.Linq.Expressions.Expression。
  17. Expression Expression { get; }
  18. //
  19. // 摘要:
  20. //     获取与此数据源关联的查询提供程序。
  21. //
  22. // 返回结果:
  23. //     与此数据源关联的 System.Linq.IQueryProvider。
  24. IQueryProvider Provider { get; }
  25. }

该接口有三个特殊的属性,具体内容代码已经介绍了,那查询时具体又是如何执行呢?

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

哎呀,写到现在终于差不多快写完了。

上面介绍了两个接口的区别与联系,具体使用哪种就看自己的项目需求了。

最后补充一下List.Where()方法,还是以代码说明。

  1. List<string> fruits =
  2. new List<string> { "apple", "passionfruit", "banana", "mango",
  3. "orange", "blueberry", "grape", "strawberry" };
  4. IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);
  5. foreach (string fruit in query)
  6. {
  7. Console.WriteLine(fruit);

查看List<T>的定义,如下图所示

它也是继承了IEnumerable接口,因此,他也不存在延迟加载。
OK,到此,所有工作完成。

深入理解IEnumerable和IQueryable两接口的区别的更多相关文章

  1. 【C#夯实】我与接口二三事:IEnumerable、IQueryable 与 LINQ

    序 学生时期,有过小组作业,当时分工一人做那么两三个页面,然而在前端差不多的时候,我和另一个同学发生了争执.当时用的是简单的三层架构(DLL.BLL.UI),我个人觉得各写各的吧,到时候合并,而他觉得 ...

  2. C# IEnumerable与IQueryable ,IEnumerable与IList ,LINQ理解Var和IEnumerable

    原文:https://www.cnblogs.com/WinHEC/articles/understanding-var-and-ienumerable-with-linq.html 使用LINQ从数 ...

  3. IEnumerable 与 IQueryable

    无论是在ado.net EF或者是在其他的Linq使用中,我们经常会碰到两个重要的静态类Enumerable.Queryable,他们在System.Linq命名空间下.那么这两个类是如何定义的,又是 ...

  4. IEnumerable和IQueryable和Linq的查询

    IEnumerable和IEnumerable 1.IEnumerable查询必须在本地执行.并且执行查询前我们必须把所有的数据加载到本地.而且更多的时候.加载的数据有大量的数据是我们不需要的无效数据 ...

  5. IEnumerable和IQueryable区别、优缺点

    转自 http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...

  6. EntityFramework IEnumerable,IQueryable ,Include

    使用IQueryable using (var db = new CentaStaffEntities()) { IQueryable<Staff> queryablestaffs = d ...

  7. IEnumerable和IQueryable的区别

    转自:http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...

  8. IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树

    关于IEnumerable和IQueryable的区别,这事还要从泛型委托Func<T>说起.来看一个简单的泛型委托例子: class Program { static void Main ...

  9. IEnumerable 与 Iqueryable 的区别

    IEnumerable 和 IQueryable   共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable<T> 的对象上运行,另一组在类型为 IQueryable&l ...

随机推荐

  1. MAC 使用技巧及常用软件备忘

    公司转向MAC快一年, 换了MAC PRO半年时间,MAC这东西除了颜值和性能,软件真是不如WINDOWS啊,不是没有,只是好多都收费! 先介绍几个跨平台的. WIN+MAC 通用: 浏览器: CHR ...

  2. 转:TensorFlow和Caffe、MXNet、Keras等其他深度学习框架的对比

    http://geek.csdn.net/news/detail/138968 Google近日发布了TensorFlow 1.0候选版,这第一个稳定版将是深度学习框架发展中的里程碑的一步.自Tens ...

  3. zStack学习笔记(原创,绝对不是抄的……)

    我之前写的文章都没写上面那句,但是这篇写了,主要是因为zStack文章抄袭太严重……故此声明 因为涉及到数据的双向交互问题,所以在这里我考虑使用协议栈来实现数据的收发.首先说下如何在Zstack中添加 ...

  4. Java Volatile keyword

    Volatile修饰的成员变量在每次被线程訪问时,都强迫从主内存中重读该成员变量的值.并且,当成员变量发生变化时,强迫线程将变化值回写到主内存.这样在不论什么时刻,两个不同的线程总是看到某个成员变量的 ...

  5. 手游产品经理初探(四)从Buybutton谈玩家付费

    付费模块一直是游戏中最最重要的一块,那么今天我们从玩家的角度来解说哪种方式付费更迎合玩家的心理.我还是着重从我做的Casino类型游戏说起. 一般来说游戏界面喜欢把付费button放在界面最醒目的位置 ...

  6. HTTP——代理协议 HTTP/1.1的CONNECT方法

    我们平时使用HTTP协议无非就是GET.POST这些方法,但是HTTP的内容远不止那些.今天就来说说HTTP代理使用的CONNECT.这个不是在网页开发上用的,如果没兴趣就跳过吧. APACHE只是作 ...

  7. selenium从入门到应用 - 7,testNG的DataProvider

    本系列所有代码 https://github.com/zhangting85/simpleWebtest 本文将介绍一个Java+TestNG+Maven+Selenium的web自动化测试脚本环境下 ...

  8. hdu1236 排名(结构体排序)

    排名 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submiss ...

  9. Jquery判断其中任意一个文本框的值是否被修改

    <!doctype html><html lang="en"> <head>  <meta charset="UTF-8&quo ...

  10. 系统管理员应该知道的 20 条 Linux 命令

    如果您的应用程序不工作,或者您希望在寻找更多信息,这 20 个命令将派上用场. 在这个全新的工具和多样化的开发环境井喷的大环境下,任何开发者和工程师都有必要学习一些基本的系统管理命令.特定的命令和工具 ...