首先一点: IQueryable interface 继承自 IEnumberable interface , 所以 IEnumberable 能做的 IQueryable 都能做;
共同点:
1、两者都是延迟加载(Lazy Loading) ,
2、EF 使用中共同的方法: where() , skip() , OrderbyDescending() , Take() etc ,
以上这些方法都有两个版本:
IEnumberable 版本: Where(Func<Customer, bool> predicate)
IQueryable 版本: Where(Expression<Func<Customer, bool>> predicate)
其中 Expression对象的Compile() 执行后 为 Func<>类型
3、. AsEnumerable() 方法 使用IEnumberalbe接口, .AsQueryable() 使用IQueryable接口
不同点:
1、IQueryable 允许 LINQ-to-SQL , 转化成的sql 语句在服务器端执行
2、IEnumberable 允许 LINQ-to-Object, 不允许转化成SQL, 只能操作内存中的数据;
下面通过代码说明:
1、使用EF中IEnumberable 接口的方法 where() 执行过滤 Empid=2的 Employess
EmpEntities ent = new EmpEntities(); IEnumerable<Employee> emp = ent.Employees; IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
这个操作 生成的SQL语句是:
SELECT * FROM [dbo].[ Employees] /// 获取所有的 Employees
执行过程是: 从数据库中获取所有的 Employees 到客户端(内存)中, 在内存中执行过滤操作(where()方法)。
执行过程如下图示:
从上可以看出: 这种 查询 方法时比较慢, 因为查询出了所有的数据;
2、 使用EF 中 IQueryable interface的方法 .where() 执行相同的操作;
EmpEntities ent = new EmpEntities(); IQueryable<Employee> emp = ent.Employees; IQueryable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
生成的SQL语句使:
SELECT TOP 1 * FROM [dbo].[ Employees] WHERE [Empid] =10
执行过程如下图所示:
这种执行方式, 通过成的SQL语句 , 在服务器端 执行过滤操作, 然后将符合条件的数据返回客户端(内存中), 而不是将所有的数据都返回到客户端,
总结:
过滤内存中的数据 IEnumberable 接口的方法随时可以使用;
查询数据库IQueryable 接口的方法,是一个比较好的选择,但是IQueryable接口方法中 使用LINQ语句, 会有一些语句不识别, 比如 自定义方法, 识别都是能够转化成sql语句的方法;
使用EF , 效率问题是必须要注意的问题,尤其是查询数据,很容造成 n+1问题 、 返回所有数据问题 , 造成查询效率低下;
PS: 上面图示部分来自 参考资料
What is the difference between IQueryable<T> and IEnumerable<T>?
Returning IEnumerable<T> vs. IQueryable<T>
英文版的 技术资料 真的很齐全, 做技术方面还是要多读英文资料;