IQueryable与IEnumberable的区别   IQueryable与IList差别之处 - TOMMYHU - 专注互联网开发及运营技术,提供相关资料及软件下载,奇趣网络时事评论!
Oct 9

IQueryable与IEnumberable的区别   IQueryable与IList差别之处 不指定

tommyhu , 17:02 , ASP.NET , Comments(0) , Trackbacks(0) , Reads(2232) , Via Original Large | Medium | Small
IQueryable与IList差别之处

IList(IList)会立即在内存里创建持久数据,这就没有实现“延期执行(deferred execution)”,如果被加载的实体有关联实体(associations),此关联实体不会被加载(既不立即加载,也不延迟加载)。

IQeurable(IQuerable)不会立即在内存里创建持久数据,只有遍历它(如通过foreach)、把它转换成List等情况下才会向内存加载数据,它可以实现“延期执行”,如果当前被加载的实体有关联实体(associations),此关联实体可被接下来的访问加载。

看下面一段代码:
//IList的情况
IList users = res.ToList(); //此时已把users加载到内存,而每个user的关联实体(UserInfos)未
                       //被加载,所以下一行代码无法顺利通过
var ss = users.Where(p => p.UserInfos.ID != 3); //此处报错,因为P的UserInfos实体无法被加载

// IQuerable的情况
IQueryable users = res.AsQueryable(); //users未被立即加载,关联实体可通过“延迟加载”获
                                   //得
var ss = users.Where(p => p.UserInfos.ID != 3);//此处顺利获得对应的ss





IEnumerable接口
公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代。也就是说:实现了此接口的object,就可以直接使用foreach遍历此object;
IQueryable 接口
它继承 IEnumerable 接口,而因为.net版本加入Linq和IQueryable后,使得IEnumerable不再那么单调,变得更加强大和丰富。
为了区别两个接口,我们通过一个实际的例子来解释一下。
根据上篇随笔的实例,编写如下代码:
复制代码
static void Main(string[] args)
        {
            //创建数据库访问网关
            using (SchoolDBEntities schoolEntities = new SchoolDBEntities())
            {
                //查询的结果放入IQueryable接口的集合中
                IQueryable classesIQue = (from c in schoolEntities.T_Class
                                                   orderby c.ID
                                                     select c).Skip(3).Take(3);
                //注意这个AsEnumerable()在分页查询之前,先将其转换成IEnumerable类型
                IEnumerable classesIEnu = (from c in schoolEntities.T_Class
                                                    orderby c.ID  
                                                    select c).AsEnumerable().Skip(3).Take(3);
                //因为启用了延迟加载机制,所以下面调用一下,才会真正去读取数据库
                int i = 0;
                foreach (var c in classesIQue)
                {
                    i++;
                }
                Console.WriteLine(i);
                foreach (var c in classesIEnu)
                {
                    i++;
                }
                Console.WriteLine(i);
            }
            Console.WriteLine("OK");
            Console.ReadKey();
        }




测试结果
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 Data Inconsistancy
复制代码
    IQueryable 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()




IList,IQeurable,IEnumble和List 的区别
IList,IQeurable,IEnumble和List 的区别主要如下:

1.IList(IList)会立即在内存里创建持久数据,这就没有实现“延期执行(deferred execution)”,而是一次性将数据加载进来,如果被加载的实体有关联实体(associations),此关联实体不会被加载(既不立即加载,也不延迟加载)

2.IQeurable(IQuerable)不会立即在内存里创建持久数据,只有遍历它(如通过foreach)、把它转换成List等情况下才会向内存加载数据,它可以实现“延期执行”,如果当前被加载的实体有关联实体(associations),此关联实体可被接下来的访问加载。在每次执行时都必须连接数据库读取,而IList读取一次后,以后各次都不需连接数据库。IQeurable 很容易造成重复读取,性能低下,并且可能引发数据不一致性



1
2
3
4
5
6
7
8
9
//IList
IList users = res.ToList(); //此时已把users加载到内存,而每个user的关联实体(UserInfos)未
                                       //被加载,所以下一行代码无法顺利通过
var ss = users.Where(p => p.UserInfos.ID != 3); //此处报错,因为P的UserInfos实体无法被加载

// IQuerable的
IQueryable users = res.AsQueryable(); //users未被立即加载,关联实体可通过“延迟加载”获
                                   //得
var ss = users.Where(p => p.UserInfos.ID != 3);//此处顺利获得对应的ss


3.IEnumberalb使用的是LINQ to Object方式,它会将AsEnumerable()时对应的所有记录都先加载到内存,然后在此基础上再执行后来的Query。

4.List <>是泛型类,它已经实现了IList <>定义的那些方法,IList list=new List();
只是想创建一个基于接口IList的对象的实例,这个接口是由List实现的。只是希望使用到IList接口规定的功能而已



总结:

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

当你打算马上使用查询后的结果(比如循环作逻辑处理或者填充到一个table/grid中),并且你不介意该查询即时被执行后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查执行,使用ToList()
当你希望查询后的结果可以供调用者(Consummer)作后续查询(比如这是一个"GetAll"的方法),或者你希望该查询延时执行,使用AsQueryable()
按照功能由低到高:List IList  IQueryable IEnumerable
按照性能由低到高:IEnumerable IQueryable IList  List
参考文档:  http://www.cnblogs.com/xpvincent/p/3605068.html

http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in_Entity_Framework.html

▲返回顶部
Last modified by tommyhu on2016/10/09 17:16

Add a comment

Nickname

emotemotemotemotemotemotemotemotemotemotemotemotemotemotemotemot