最近在修项目的历史代码,发现搞混了很多拓展方法,写一篇博客澄清一下。
概念需要:iqueryable不应该和ienumerable比而应该和ilist比,ienumerable是这两者的父接口。
问题:IQueryable, IEnumerable的?
(1)所有对于IEnumerable的过滤、排序、分组、聚合等操作,都是在内存中进行的。也就是说把所有的数据不管用不用得到,都从数据库倒入内存中,只是在内存中进行过滤和排序操作,但性能很高,空间换时间,用于操作本地数据源。
(2)所有对于IQueryable的过滤、排序、分组、聚合等操作,只有在数据真正用到的时候才会到数据库中查询,以及只把需要的数据筛选到内存中。Linq to SQL引擎会把表达式树转化成相应的SQL在数据库中执行,这也是Linq的延迟加载核心思想所在,在很复杂的操作下可能比较慢了,时间换空间。
(3)操作本地数据源用IEnumerable,操作远程数据源用IQueryable
问题:IQueryable接口的特殊之处?
它继承自IEnumerable,:Expression会把查询表达式生成表达式树缓存起来,只有当真正需要用到的时候,才会由IQueryProvider解析表达式树,翻译成sql语句执行数据库查询操作。而Func是个委托,必须要先执行完才能进行下一个方法的调用。
更直白点的说,就是:IQueryable是负责生成SQL语句的,但并不马上执行;而IEnumerable是对任意类型的集合都能操作的,不限于是数据库还是一般的Array还是List。
问题:关于List<T>
List<T>也继承自IEnumerable,所以Where、OrderBy这些方法也能用,同时,List<T>它也是继承了IEnumerable接口,所以,它也不是延迟加载的,但支持延迟查询。
勘误:拓展方法的入参
①IQueryable和IEnumerable
IQueryable
延时执行;扩展方法接受的是Expression(必须要能转成sql,否则报错)
IEnumerable
延时执行;扩展方法接受的是Func(C#语法)
Func是. NET类库从3.0开始新增的内置委托,用于实现返回类型为任何有返回类型的函数的调用。 Func的参数列表的格式为传入类型参数列表+返回列表。
IEnumerable.Where 参数为 Func,如果使用下面的写法, ctx.Books 作为 IQueryable 类型会向上转型为 IEnumerable
这也解释了IQueryble与IEnumerable的一个区别,因为IQueryble里定义了表达式树,所以也解释了它为什么能够实现服务器端过滤。
所以,我犯下的错误在这