Entity Framework中IQueryable, IEnumerable, IList的区别(转载)
原文: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()
Entity Framework中IQueryable, IEnumerable, IList的区别(转载)的更多相关文章
- Entity Framework中IQueryable, IEnumerable, IList的区别[转]
使用工具追踪EF生成的SQL 使用Entity Framework等ORM框架的时候,SQL对于使用者来说是透明的,往往很多人也不关心ORM所生成的SQL,然而系统出现性能问题的时候就必须关注生成的S ...
- Entity Framework中IQueryable, IEnumerable, IList的区别
博客园里有这样的总结.这里姑且先列个题目, 提醒自己记忆.
- Entity Framework中使用IEnumerable<T>、IQueryable<T>及IList<T>的区别
1. IEnumerable<T> IEnumerable<T> :对于在内存中集合上运行的方法,返回的可枚举对象将捕获传递到方法的参数.在枚举该对象时,将使用查询运算符的逻辑 ...
- Entity framework 中Where、First、Count等查询函数使用时要注意
在.Net开发中,Entity framework是微软ORM架构的最佳官方工具.我们可以使用Lambda表达式在Entity framework中DbSet<T>类上直接做查询(比如使用 ...
- Entity Framework 教程——Entity Framework中的实体类型
Entity Framework中的实体类型 : 在之前的章节中我们介绍过从已有的数据库中创建EDM,它包含数据库中每个表所对应的实体.在EF 5.0/6.0中,存在POCO 实体和动态代理实体两种. ...
- [转]在Entity Framework中使用LINQ语句分页
本文转自:http://diaosbook.com/Post/2012/9/21/linq-paging-in-entity-framework 我们知道,内存分页效率很低.并且,如果是WebForm ...
- Lazy<T>在Entity Framework中的性能优化实践
Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...
- 关于Entity Framework中的Attached报错相关解决方案的总结
关于Entity Framework中的Attached报错的问题,我这里分为以下几种类型,每种类型我都给出相应的解决方案,希望能给大家带来一些的帮助,当然作为读者的您如果觉得有不同的意见或更好的方法 ...
- 关于Entity Framework中的Attached报错的完美解决方案终极版
之前发表过一篇文章题为<关于Entity Framework中的Attached报错的完美解决方案>,那篇文章确实能解决单个实体在进行更新.删除时Attached的报错,注意我这里说的单个 ...
随机推荐
- Sword STL迭代器prev,next相关函数
迭代器的头文件中定义了4个实现迭代器模板的函数模板. .advance(iterator,num):将迭代器iterator 移动了num个位置 .distance(iterator1,iterato ...
- Java反射,参数为数组
使用反射调用非公开的方法有时能解决许多问题,如果方法的参数是数组时类型该怎么传递呢?这里找到了一种方法记录一下 实例 比如: class A{ private void sayHello(String ...
- 关于CLOS架构的举例 网络级 设备级 FATTREE网络 网络级CLOS 以及CLOS涉及的调度算法RR
1.概述 CLOS来自于传统电路交换概念,这个概念年代太久远,在当前数据通信网络中,内涵有所变化.本文主要谈的是实际上赋予的与原来略微有所差异的内涵. CLOS架构本身概念比较宽泛,有设备级的CLOS ...
- Java8学习笔记(八)--方法引入的补充
在Java8学习笔记(三)--方法引入中,简要总结了方法引入时的使用规则,但不够完善.这里补充下几种情况: 从形参到实例方法的实参 示例 public class Example { static L ...
- Angular4学习笔记(八)- ng-content
内容投影 ng-content ng-content是一个占位符,有些类似于router-outlet. 以前举の例子,父组件包含子组件都是直接指明子组件的selector,比如子组件的selecto ...
- 解决java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone
使用spring boot整合MySQL时一直报 java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecog ...
- 总结一下搭建简单Web服务器的一些方法
使用nodejs+anywhere模块搭建静态文件服务器 anywhere随时随地将你的当前目录变成一个静态文件服务器的根目录. 安装npm install anywhere -g,然后进入任意目录在 ...
- 艺多不压身 -- 常用缓存Cache机制的实现
常用缓存Cache机制的实现 缓存,就是将程序或系统经常要调用的对象存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例. 这样做可以减少系统开销,提高系统效率. 缓存主要可分为二大类: ...
- PHP在linux读取word文档
几天帮朋友解决一个技术问题,在Linux下,将word文档中的内容读取,然后使用正则匹配,拼成sql入库 查阅了外文资料和google之后,步骤如下: #wget http://www.winfiel ...
- 【python】并查集
转自:http://blog.csdn.net/rav009/article/details/12781899 # -*- coding: UTF-8 -*- class unionfind: def ...