Linq查询IEnumerable与IQueryable

 class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch stp = new Stopwatch();



            using(var db = new DBCommonContext();){
                stp.Start();
                var usser_First = db.tbUsers.Where(p => p.UserID > 0);//.AsEnumerable();
            var users_Now = usser_First.Where(p => p.ModifyDate > new DateTime(2012, 8, 2)); //断点
            foreach (var user in users_Now)
            {//断点
                Console.WriteLine(user.UserName + "\n");

            }

            stp.Stop();
            Console.WriteLine("IQueryable执行时间:" + stp.Elapsed.ToString()+"\n");
            stp.Reset();
            }
            Console.ReadKey();


        }
    }

设置好断点,打开SQL Profiler。分别对两个跟踪,可以看到到第一个断点的时候都还没有去SQL拿数据:
这里写图片描述

都是延迟执行,从SQL Profiler可以看出都是到foreach才去拿数据。

①、IEnumerable下执行的语句,可以看到去SQL加载过来的是第一个条件下的所有数据,然后扩展方法筛选。本质Linq2object,数据量略大内存占用多,响应速度也略快。

这里写图片描述

②、IQueryable下的结果,是根据语法书整个合并成sql查询到结果。本质linq2sql,耗损小,但查询效率略慢
这里写图片描述

组合查询的时候,我们一般会采取IQueryable<T>,最后ToList()的时候才会去数据库拿数据

...........
        using (var db = new YourEntitys())
                {
                    //linq组合查询
                    var query = from a in db.YourTable
                        select a;

                    if (YourTableDto.SystemId>0)
                    {
                        query = query.Where(p=>p.Id==YourTableDto.Id);
                    }
                    if (!string.IsNullOrEmpty(YourTable.Name))
                    {
                        query = query.Where(p => p.Name.Contains(YourTableDto.CategoryName));
                    }

..........

直接总结:

IEnumerable<T>会直接加载所有数据到内存,然后再筛选。是先从数据库取出数据放入内存,然后在本地调用SKipTake 等扩展方法

在调用自己的Where、SKip 、Take 等扩展方法之前数据就已经加载在本地内存里了。如上按第一个条件直接SQL加载到内存后,再自身执行第二个条件的数据。所以它传输的数据量比较大,所以会有更多的无用功。本质Linq2Object,额外带宽耗损大但速度快占内存。内存的读取速度要高于数据库之间筛选的速度

IQueryable<T> 会先翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。

所以在使用ORM、linq等的时候注意这两个接口,考虑好内存

是通过语法树完全转换成一个T-sql语句,最后SQL拿到结果集。只加载需要的数据。本质Linq2SQL。耗损小速度略慢。

选择哪个的问题其实是远程从sql加载数据和本地加载筛选数据的取舍


IEnumerable<T>IQueryable<T>区分

LINQ查询方法一共提供了两种扩展方法,在System.Linq命名空间下,有两个静态类:Enumerable类,它针对继承了IEnumerable<T>接口的集合进行扩展;Queryable类,针对继承了IQueryable<T>接口的集合进行扩展。我们会发现接口IQueryable<T>实际也是继承了IEnumerable<T>接口的,既然这样微软为什么要设计出两套扩展方法呢?

从LINQ查询功能上我们知道实际上可以分为三类:LINQ to OBJECTSLINQ to SQLLINQ to XML。其实微设计这两套接口主要是针对LINQ to OBJECTSLINQ to SQL,两者对于查询的内部处理机制是完全不同的。针对LINQ to OBJECTS 时,使用Enumerable中的扩展方法对本地集合进行排序和查询操作,查询参数接受的是Func<>Func<>叫做谓语表达式,相当于一个委托。针对LINQ to SQL时,则使用Queryable中的扩展方法,它接受的是Expression<>

那么,到底什么时候使用IQueryable<T>,什么时候使用IEnumerable<T>

首先我们来看一下LINQ to SQL的代码:

using (var context = new NorthwindEntities())

{

var orderTmp = context.Orders.Where(p=>p.CustomerID=="RATTC");

var orders = orderTmp.Where(p => p.OrderDate > new DateTime(1997, 1, 1));

foreach (var order in orders)

{

Console.WriteLine("OrderId:" + order.OrderID);

}

}

通过vs的Intellisense我们可以看到Where的返回类型为IQueryable,参数是Expression类型的:
这里写图片描述
我们再看一下这一段代码:

using (var context = new NorthwindEntities())

{

var orderTmp = context.Orders.Where(p => p.CustomerID == "RATTC").AsEnumerable();

var orders = orderTmp.Where(p => p.OrderDate > new DateTime(1997, 1, 1));

foreach (var order in orders)

{

Console.WriteLine("OrderId:" + order.OrderID);

}

}

这段代码的不同在于我们将LINQ的查询返回IEnumerable类型,我们看一下vs的Intellisense效果:
这里写图片描述

由于我们在LINQ查询的时候加上了AsEnumerable(),因此我们在第二条语句能看到返回类型已经变为IEnumerable,参数也变成了Func<>类型。

至于这两段代码到底有什么区别,我们分别执行代码,在sql profiler里看一下生成的sql语句:

第一段代码效果:
这里写图片描述

虽然我们使用两条语句进行了查询,但最终只生成了一条SQL语句,将查询参数合并了。

第二代码效果:
这里写图片描述

这一次我们依然只看到一条SQL语句,但查询条件也只有一个,但两次查询的结果是一致。

原因在于Func<>直接会被编译器编译成IL代码,但是Expression<>只是存储了一个表达式树,在运行期作处理,LINQ to SQL最终会将表达式树转为相应的SQL语句,然后在数据库中执行。

现在我们应该知道何时使用IEnumerable<T>,何时使用Iqueryable<T>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值