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);
}
}
}

测试结果

  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条详情。

    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的区别的更多相关文章

  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. Android wakelock机制

      Wake Lock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得. 这个锁可以是有超时的或者是没有超时的,超时的锁会在时间过去以后自动解锁. 如果没有锁了或者 ...

  2. 基于XMPP的即时通信系统的建立(六)— 开发环境搭建

    服务器端 新建空工程 使用Eclipse新建名为openfire的空java工程. 导入源代码 这里使用的是openfire的openfire_src_3_10_3.zip源码. 导入后将目录src/ ...

  3. 获取本机外网ip和内网ip

    获取本机外网ip //获取本机的公网IP public static string GetIP() { string tempip = ""; try { WebRequest r ...

  4. mybatis源码分析(1)——SqlSessionFactory实例的产生过程

    在使用mybatis框架时,第一步就需要产生SqlSessionFactory类的实例(相当于是产生连接池),通过调用SqlSessionFactoryBuilder类的实例的build方法来完成.下 ...

  5. ASP.NET MVC Html.ActionLink使用说明

    本文整理了该方法的几种重载形式: 1.Html.ActionLink("linkText","actionName")该重载的第一个参数是该链接要显示的文字,第 ...

  6. Android平台调用WebService详解

    上篇文章已经对Web Service及其相关知识进行了介绍(Android开发之WebService介绍 ),相信有的朋友已经忍耐不住想试试在Android应用中调用Web Service.本文将通过 ...

  7. Java [Leetcode 144]Binary Tree Preorder Traversal

    题目描述: Given a binary tree, return the preorder traversal of its nodes' values. For example:Given bin ...

  8. poj 2184 Cow Exhibition

    // 给定n头牛,每头有属性智商和幽默感,这两个属性值有正有负,现在要从这n头牛中选出若干头使得他们的智商和与幽默感和不为负数,// 并且两者两家和最大,如果无解输出0,n<=100,-1000 ...

  9. ADO.NET访问SQL Server调用存储过程带回参

    1,ADO.NET访问SQL Server调用存储过程带回参 2,DatabaseDesign  use northwind go --存储过程1 --插入一条商品 productname=芹菜 un ...

  10. 20、内存溢出(Out of Memory)

     内存引用(释放强引用) Object obj=new Object(); obj = null;  内存引用(使用软引用) 软引用是主要用于内存敏感的高速缓存.在jvm报告内存不足之前会清 除所 ...