EF入门 IQueryable和IEnumberable的区别
IEnumerable接口
公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代。也就是说:实现了此接口的object,就可以直接使用foreach遍历此object;
IQueryable 接口
它继承 IEnumerable 接口,而因为.net版本加入Linq和IQueryable后,使得IEnumerable不再那么单调,变得更加强大和丰富。
为了区别两个接口,我们通过一个实际的例子来解释一下。
编写如下代码:
static void Main(string[] args)
{
//创建数据库访问网关
using (SchoolDBEntities schoolEntities = new SchoolDBEntities())
{
//查询的结果放入IQueryable接口的集合中
IQueryable<T_Class> classesIQue = (from c in schoolEntities.T_Class
orderby c.ID
select c).Skip<T_Class>().Take<T_Class>();
//注意这个AsEnumerable<T_Class>()在分页查询之前,先将其转换成IEnumerable类型
IEnumerable<T_Class> classesIEnu = (from c in schoolEntities.T_Class
orderby c.ID
select c).AsEnumerable<T_Class>().Skip<T_Class>().Take<T_Class>();
//因为启用了延迟加载机制,所以下面调用一下,才会真正去读取数据库
int i = ;
foreach (var c in classesIQue)
{
i++;
}
Console.WriteLine(i);
foreach (var c in classesIEnu)
{
i++;
}
Console.WriteLine(i);
}
Console.WriteLine("OK");
Console.ReadKey();
}
注意红色代码部分,在用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。
private static void TestIQueryable()
{
using (var ctx = new WrappedNorthWindEntities())
{
IQueryable<Product> expression = ctx.Products.Take();
IQueryable<Product> products = expression.Take(); // A 不执行SQL
Console.WriteLine(products.Count()); // B SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
Console.WriteLine(products.Count()); // C SELECT COUNT(1) FROM ( SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] ))
foreach (Product p in products) // D SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products]
{
Console.WriteLine(p.ProductName);
}
foreach (Product p in products) // E SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] )
{
Console.WriteLine(p.ProductName);
}
}
}
private static void TestIEnumerable()
{
using (var ctx = new WrappedNorthWindEntities())
{
IEnumerable<Product> expression = ctx.Products.Take().AsEnumerable();
IEnumerable<Product> products = expression.Take(); // A 不执行SQL
Console.WriteLine(products.Count()); // B SELECT TOP (5) * FROM [dbo].[Products]
Console.WriteLine(products.Count()); // C SELECT TOP (5) * FROM [dbo].[Products]
foreach (Product p in products) // D SELECT TOP (5) * FROM [dbo].[Products]
{
Console.WriteLine(p.ProductName);
}
foreach (Product p in products) // E SELECT TOP (5) * FROM [dbo].[Products]
{
Console.WriteLine(p.ProductName);
}
}
}
private static void TestIList()
{
using (var ctx = new WrappedNorthWindEntities())
{
var expression = ctx.Products.Take();
IList<Product> products = expression.Take().ToList(); // A SELECT TOP (2) * FROM ( SELECT TOP (5) * FROM [dbo].[Products] Console.WriteLine(products.Count()); // B 不执行SQL
Console.WriteLine(products.Count()); // C 不执行SQL
foreach (Product p in products) // D 不执行SQL
{
Console.WriteLine(p.ProductName);
}
foreach (Product p in products) // E 不执行SQL
{
Console.WriteLine(p.ProductName);
}
}
}
测试结果
- IQueryable和IEnumerable都是延时执行(Deferred Execution)的,而IList是即时执行(Eager Execution)
- IQueryable和IEnumerable在每次执行时都必须连接数据库读取,而IList读取一次后,以后各次都不需连接数据库。前两者很容易造成重复读取,性能低下,并且可能引发数据不一致性
- IQueryable和IEnumerable的区别:IEnumberalb使用的是LINQ to Object方式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此基础上再执行后来的Query。所以上述TestIEnumerable例子中执行的SQL是"select top(5) ...",然后在内存中选择前两条记录返回。
以下是一个IQueryable引发数据不一致性的例子:记录总数和记录详情两者本应一致,但由于IQueryable前后两次读取数据库,结果是现实有10条记录,却输出11条详情。
IQueryable<Product> products = ctx.Products.All();
//开始的时候数据库product表中有10条记录, count = 10
int count = products.Count();
Console.WriteLine("Count of products:"+count); //此时另一进程添加一个产品进数据库
//会重新读取数据库并输出11个产品名称
foreach (Product p in products)
{
Console.WriteLine(p.ProductName);
}
结论
基于性能和数据一致性这两点,我们使用IQueryable时必须谨慎,而在大多数情况下我们应使用IList。
- 当你打算马上使用查询后的结果(比如循环作逻辑处理或者填充到一个table/grid中),并且你不介意该查询会即时执行,使用ToList()
- 当你希望查询后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查询延时执行,使用AsQueryable()
EF入门 IQueryable和IEnumberable的区别的更多相关文章
- Entity Framework快速入门--IQueryable与IEnumberable的区别
IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...
- Entity Framework快速入门--IQueryable与IEnumberable的区别(转载)
IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...
- C#中IQueryable和IEnumberable的区别
IQueryable和IEnumberable的区别主要在查询方面有区别 IQueryable查询时间是先把skip和Take翻译成sql语句,去数据库执行完成后把数据加载到内存中 IEnumbera ...
- IQueryable与IEnumberable的区别
IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 ...
- IQueryable与IEnumberable的区别(转)
转自 http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型 ...
- IQueryable 和IEnumberable的区别
一.IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单的迭代.即:实现了此接口的object,就可以使用foreach遍历该object: 二.IQueryable 接口 ...
- IQueryable 与 IEnumberable 接口的区别
IQueryable 与 IEnumberable 接口的区别是: IEnumberable<T> 泛型类在调用自己的 SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了, ...
- Entity Framework中IQueryable, IEnumerable, IList的区别[转]
使用工具追踪EF生成的SQL 使用Entity Framework等ORM框架的时候,SQL对于使用者来说是透明的,往往很多人也不关心ORM所生成的SQL,然而系统出现性能问题的时候就必须关注生成的S ...
- Entity Framework中IQueryable, IEnumerable, IList的区别(转载)
原文:http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in ...
随机推荐
- Python模块整理(三):子进程模块subprocess
文章 原始出处 http://ipseek.blog.51cto.com/1041109/807513. 本来收集整理网络上相关资料后整理: 从python2.4版本开始,可以用subprocess这 ...
- ASP.NET MVC 学习3、Controller左手从Model获取数据,右手传递到View页面
参考:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/accessing-your-models-dat ...
- Struts2配置
1. 设定server a) window– preferences – myeclipse – servers – tomcat – 6.x b) 选择tomcat h ...
- HDU 2444 The Accomodation of Students (偶图判定,匈牙利算法)
题意: 有一堆的学生关系,要将他们先分成两个组,同组的人都不互不认识,如果不能分2组,输出No.若能,则继续.在两组中挑两个认识的人(每组各1人)到一个双人房.输出需要多少个双人房? 思路: 先判定是 ...
- 【C#学习笔记】获得系统时间
using System; namespace ConsoleApplication { class Program { static void Main(string[] args) { Conso ...
- shell 中grep命令详解
用‘grep’搜索文本文件如果您要在几个文本文件中查找一字符串,可以使用‘grep’命令.‘grep’在文本中搜索指定的字符串.举个例子:假设您正在‘/usr/src/linux/Documentat ...
- 基于RTP的H264视频数据打包解包类
from:http://blog.csdn.net/dengzikun/article/details/5807694 最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打 ...
- 【Mysql】命令行
查看数据库->show databases; 建数据库->create database 数据库名; 建表->use 数据库名;->create table 表名(字段); 查 ...
- w3c盒子模型与ie盒子模型
盒子模型是css的专有名词,用来描述页面设置中的各种属性,如内容(content).填充(padding).边框(border).边界(margin),由于这些属性拼在一起,与日常生活中的“盒子”很相 ...
- wifi详解(三)
1 WLAN驱动结构介绍 1.1 SDIO驱动 在drivers/mmc下面是mmc卡,SD卡和SDIO卡驱动部分,其中包括host驱动,card驱动和core部分,由于网络接 ...