IEnumerable接口

公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代。也就是说:实现了此接口的object,就可以直接使用foreach遍历此object;

IQueryable 接口

它继承 IEnumerable 接口,而因为.net版本加入Linq和IQueryable后,使得IEnumerable不再那么单调,变得更加强大和丰富。

为了区别两个接口,我们通过一个实际的例子来解释一下。

编写如下代码:

  1. static void Main(string[] args)
  2. {
  3. //创建数据库访问网关
  4. using (SchoolDBEntities schoolEntities = new SchoolDBEntities())
  5. {
  6. //查询的结果放入IQueryable接口的集合中
  7. IQueryable<T_Class> classesIQue = (from c in schoolEntities.T_Class
  8. orderby c.ID
  9. select c).Skip<T_Class>().Take<T_Class>();
  10. //注意这个AsEnumerable<T_Class>()在分页查询之前,先将其转换成IEnumerable类型
  11. IEnumerable<T_Class> classesIEnu = (from c in schoolEntities.T_Class
  12. orderby c.ID
  13. select c).AsEnumerable<T_Class>().Skip<T_Class>().Take<T_Class>();
  14. //因为启用了延迟加载机制,所以下面调用一下,才会真正去读取数据库
  15. int i = ;
  16. foreach (var c in classesIQue)
  17. {
  18. i++;
  19. }
  20. Console.WriteLine(i);
  21. foreach (var c in classesIEnu)
  22. {
  23. i++;
  24. }
  25. Console.WriteLine(i);
  26. }
  27. Console.WriteLine("OK");
  28. Console.ReadKey();
  29. }

注意红色代码部分,在用linq查询实体集合之前我先将其转换成  IEnumerable接口类型,看看最终执行的sql是怎样的。

第一种:直接返回 IQueryable类型的查询,如下图所示:

第二种:在用分页查询之前先将其转换成 IEnumerable实际执行的sql如下图所示:

总结

IQueryable接口与IEnumberable接口的区别:  IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable<T> 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。

以下转载地址  http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in_Entity_Framework.html

使用工具追踪EF生成的SQL

使用Entity Framework等ORM框架的时候,SQL对于使用者来说是透明的,往往很多人也不关心ORM所生成的SQL,然而系统出现性能问题的时候就必须关注生成的SQL以发现问题所在。

使用过Toplink的朋友知道很只要设置日志打印级别=FINE就可以配置使之生成的SQL在服务器中打印出来,Entiry Framework没有那么幸运,在以前要检测生成SQL的唯一方法是SQL Server Profiler,但使用起来并不方便,结果也不能自动保存到文件中。

Tracing and Caching Provider Wrappers for Entity Framework是Entity Framework Team新推出的开源SQL追踪和二级缓存的解决方案。原理是在负责执行具体SQL语句的data provider(SqlClient或者其他Client)之上插入了一层WrappingProvider,用于监控DbCommand.ExecuteReader(), ExecuteScalar() and ExecuteNonQuery(),将Sql命令输出到指定介质或者将查询结果缓存起来以重用。

使用方法很简单,下载源代码编译后将dll添加到项目中,新加一个类WrappedNorthWindEntities继承原有的Entities即可,详见源代码中的示例。

测试IQueryable, IEnumerable, IList的区别

下面我们使用EF Wrapper来监测Entify Framework中IQueryable, IEnumerable和IList所生成的SQL。

  1. private static void TestIQueryable()
  2. {
  3. using (var ctx = new WrappedNorthWindEntities())
  4. {
  5. IQueryable<Product> expression = ctx.Products.Take();
  6. IQueryable<Product> products = expression.Take(); // A 不执行SQL
  7. Console.WriteLine(products.Count());          // B SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
  8. Console.WriteLine(products.Count());          // C SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
  9. foreach (Product p in products)             // D SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]
  10. {
  11. Console.WriteLine(p.ProductName);
  12. }
  13. foreach (Product p in products)             // E SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )
  14. {
  15. Console.WriteLine(p.ProductName);
  16. }
  17. }
  18. }
  1. private static void TestIEnumerable()
  2. {
  3. using (var ctx = new WrappedNorthWindEntities())
  4. {
  5. IEnumerable<Product> expression = ctx.Products.Take().AsEnumerable();
  6. IEnumerable<Product> products = expression.Take(); // A 不执行SQL
  7. Console.WriteLine(products.Count());          // B SELECT TOP (5) * FROM [dbo].[Products]
  8. Console.WriteLine(products.Count());          // C SELECT TOP (5) * FROM [dbo].[Products]
  9. foreach (Product p in products)             // D SELECT TOP (5) * FROM [dbo].[Products]
  10. {
  11. Console.WriteLine(p.ProductName);
  12. }
  13. foreach (Product p in products)             // E SELECT TOP (5) * FROM [dbo].[Products]
  14. {
  15. Console.WriteLine(p.ProductName);
  16. }
  17. }
  18. }
  1. private static void TestIList()
  2. {
  3. using (var ctx = new WrappedNorthWindEntities())
  4. {
  5. var expression = ctx.Products.Take();
  6. IList<Product> products = expression.Take().ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]
  7.  
  8. Console.WriteLine(products.Count());           // B 不执行SQL
  9. Console.WriteLine(products.Count());           // C 不执行SQL
  10. foreach (Product p in products)              // D 不执行SQL
  11. {
  12. Console.WriteLine(p.ProductName);
  13. }
  14. foreach (Product p in products)             // E 不执行SQL
  15. {
  16. Console.WriteLine(p.ProductName);
  17. }
  18. }
  19. }

测试结果

  1. IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution)
  2. IQueryable和IEnumerable在每次执行时都必须连接数据库读取,而IList读取一次后,以后各次都不需连接数据库。前两者很容易造成重复读取,性能低下,并且可能引发数据不一致性
  3. IQueryable和IEnumerable的区别:IEnumberalb使用的是LINQ to Object方式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此基础上再执行后来的Query。所以上述TestIEnumerable例子中执行的SQL是"select top(5) ...",然后在内存中选择前两条记录返回。

以下是一个IQueryable引发数据不一致性的例子:记录总数和记录详情两者本应一致,但由于IQueryable前后两次读取数据库,结果是现实有10条记录,却输出11条详情。

  1. IQueryable<Product> products = ctx.Products.All();
  2. //开始的时候数据库product表中有10条记录, count = 10
  3. int count = products.Count();
  4. Console.WriteLine("Count of products:"+count);
  5.  
  6. //此时另一进程添加一个产品进数据库
  7. //会重新读取数据库并输出11个产品名称
  8. foreach (Product p in products)
  9. {
  10. Console.WriteLine(p.ProductName);
  11. }

结论

基于性能和数据一致性这两点,我们使用IQueryable时必须谨慎,而在大多数情况下我们应使用IList。

  • 当你打算马上使用查询后的结果(比如循环作逻辑处理或者填充到一个table/grid中),并且你不介意该查询会即时执行,使用ToList()
  • 当你希望查询后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查询延时执行,使用AsQueryable()

EF入门 IQueryable和IEnumberable的区别的更多相关文章

  1. Entity Framework快速入门--IQueryable与IEnumberable的区别

    IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...

  2. Entity Framework快速入门--IQueryable与IEnumberable的区别(转载)

    IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...

  3. C#中IQueryable和IEnumberable的区别

    IQueryable和IEnumberable的区别主要在查询方面有区别 IQueryable查询时间是先把skip和Take翻译成sql语句,去数据库执行完成后把数据加载到内存中 IEnumbera ...

  4. IQueryable与IEnumberable的区别

    IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...

  5. IQueryable与IEnumberable的区别(转)

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

  6. IQueryable 和IEnumberable的区别

    一.IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单的迭代.即:实现了此接口的object,就可以使用foreach遍历该object: 二.IQueryable 接口 ...

  7. IQueryable 与 IEnumberable 接口的区别

    IQueryable 与 IEnumberable 接口的区别是: IEnumberable<T> 泛型类在调用自己的 SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了, ...

  8. Entity Framework中IQueryable, IEnumerable, IList的区别[转]

    使用工具追踪EF生成的SQL 使用Entity Framework等ORM框架的时候,SQL对于使用者来说是透明的,往往很多人也不关心ORM所生成的SQL,然而系统出现性能问题的时候就必须关注生成的S ...

  9. Entity Framework中IQueryable, IEnumerable, IList的区别(转载)

    原文:http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in ...

随机推荐

  1. 1176. Hyperchannels(欧拉回路)

    1176 给定一有向图 求其反图的欧拉回路 路径输反了 一直WA.. #include <iostream> #include<cstdio> #include<cstr ...

  2. RAPIDXML 中文手册,根据官方文档完整翻译!

    简介:这个号称是最快的DOM模型XML分析器,在使用它之前我都是用TinyXML的,因为它小巧和容易上手,但真正在项目中使用时才发现如果分析一个比较大的XML时TinyXML还是表现一般,所以我们决定 ...

  3. abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

    abstract的method不可以是static的,因为抽象的方法是要被子类实现的,而static与子类扯不上关系! native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类实 ...

  4. Qt之进程间通信(TCP/IP)

    简述 可以通过Qt提供的IPC使用TCP/IP,使用QtNetwork模块即可实现,TCP/IP在实现应用程序和进程内部通信或与远程进程间的通信方面非常有用. QtNetwork模块提供的类能够创建基 ...

  5. css配合js模拟的select下拉框

    css配合js模拟的select下拉框 <!doctype html> <html> <head> <meta charset="utf-8&quo ...

  6. 实现窗口逐渐增大(moveTo(),resizeTo(),resizeBy()方法)

    moveTo()方法格式:window.moveTo(x,y); 功能:将窗口移动到指定坐标(x,y)处; resizeTo()方法格式:window.resizeTo(x,y); 功能:将当前窗口改 ...

  7. 反转链表 --剑指offer

    题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反正后链表的头结点. #include<stdio.h> #include<malloc.h> typedef str ...

  8. IOS PUSH

    第一阶段:.net应用程序把要发送的消息.目的iPhone的标识打包,发给APNS. 第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPh ...

  9. 遍历 集合 Dictionary 的时候修改集合 方法

    Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("1" ...

  10. UTF编码问题小结

    在编程当中经常出现乱码的问题,而由此一般会引发很多惨剧,如读文件不成功.用户名显示乱码等,所以端午节抽了一小点时间好好看了一下编码问题,以备遗忘. 首先是中文编码,除了台湾和香港常用的BIG5,国内大 ...