核心区别:
IQueryable该接口会把查询表达式先缓存到表达式树Expression 中,只有当真正用到数据的时候(例如 遍历 ),才会由IQueryProvider解析表达式树,生成sql语句执行数据库查询操作。(离线集合)
IEnumable 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代。也就是说:实现了此接口的object,就可以直接使用foreach遍历此object;(本地集合)
(1)所有对于IEnumerable的过滤,排序等操作,都是在内存中发生的。也就是说数据已经从数据库中获取到了内存中,只是在内存中进行过滤和排序操作。
(2)所有对于IQueryable的过滤,排序等操作,只有在数据真正用到的时候才会到数据库中查询。这也是Linq的延迟加载核心所在。
案例一:
先上代码
- private void Form1_Load(object sender, EventArgs e)
- {
- using (DemoContext context = new DemoContext())
- {
- var customer = context.cunstomer.Where(c => c.Name == "牡丹");
- foreach (var item in customer)
- {
- MessageBox.Show(item.Id.ToString());
- }
- }
- }
至于代码中的上下文定义以及实体集大家不必纠结,我们在这里要透过表象看本质。在上面的程序中添加断点,同时启动sql server profiler监视工具,运行程序。
程序会在断点处停下来,如下所示
上面只是到点断点处,当然断点处的语句还有执行,继续单步执行。
执行过断点处所在的语句,观察监视工具还是什么都没有。
咦,是不是出什么问题了呢?为什么没有查询语句执行呢?真的是监视工具出问题了吗?
继续单步调试
咦,这个时候怎么出现sql查询语句了。很奇怪吧,这就是ado.net EF的延迟加载技术,这里面很重要的一部分就是通过IQueryable接口实现的(具体我们放到最后再说)。
讲过了Queryable类的Where方法,接下来我们再来看一下Enumable类的Where方法。
修改上面的代码如下所示
- private void Form1_Load(object sender, EventArgs e)
- {
- using (DemoContext context = new DemoContext())
- {
- var customer = context.cunstomer.Where(c => c.Name == "牡丹").AsEnumerable();
- foreach (var item in customer)
- {
- MessageBox.Show(item.Id.ToString());
- }
- }
- }
同样是打开监视工具,添加断点,运行程序
单步调试,继续运行
执行过断点所在的语句及执行了查询语句。
关于上面的两个测试总结如下。
(1)所有对于IEnumerable的过滤,排序等操作,都是在内存中发生的。也就是说数据已经从数据库中获取到了内存中,只是在内存中进行过滤和排序操作。
(2)所有对于IQueryable的过滤,排序等操作,只有在数据真正用到的时候才会到数据库中查询。这也是Linq的延迟加载核心所在。
案例二:
//linq 表达式的返回值的类型是IQueryable IQueryable<HKSJ_USERS> temp = from u in dbContext.HKSJ_USERS where u.ID > 4 select u; //初始化了一下IQueryable接口里面的三个参数作用: // 1 linq表达式转成表达式树Expression // 2 给元素类型 Type ElementType赋值,这里指的是<HKSJ_USERS> // 3 给提供者IQueryProvider Provider赋值,这里是efProvider,若是XML那就是xmlProvider,若是string 就stringProvider
所以理论上linq可以无限扩展。 //当用到 IQueryable接口的集合的数据的时候,provider解析Expression然后获取相应的数据。进行遍历执行。 //linq to ef:查询是在数据库端进行过滤。 foreach (var hksjUsers in temp) { Console.WriteLine(hksjUsers.ID + " " + hksjUsers.UserName); } //IEnumable内存里面过滤:把数据库中的所有的数据都查询到程序里面来之后,再进行过滤。 //linq to object var demoList = from u in dbContext.HKSJ_USERS.AsIEnumable() //ToList() where u.ID > 4 select u; foreach (var hksjUsers in demoList) { }
//List集合、Arrary,Dictionary,....都继承与IEnumable接口。
案例三
//查询的结果放入IQueryable接口的集合中 IQueryable<T_Class> classesIQue = (from c in schoolEntities.T_Class orderby c.ID select c).Skip<T_Class>(3).Take<T_Class>(3); //注意这个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>(3).Take<T_Class>(3);
IQueryable接口(F12查看)
namespace System.Linq
{
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryProvider Provider { get; }
}
}
IEnumerable接口(F12查看)
namespace System.Collections { // // 摘要: // Exposes an enumerator, which supports a simple iteration over a non-generic collection.To // browse the .NET Framework source code for this type, see the Reference Source. [ComVisible(true)] [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")] public interface IEnumerable { // // 摘要: // Returns an enumerator that iterates through a collection. // // 返回结果: // An System.Collections.IEnumerator object that can be used to iterate through // the collection. [DispId(-4)] IEnumerator GetEnumerator(); } }
namespace System.Collections { // // 摘要: // Supports a simple iteration over a non-generic collection. [ComVisible(true)] [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] public interface IEnumerator { // // 摘要: // Gets the current element in the collection. // // 返回结果: // The current element in the collection. object Current { get; } // // 摘要: // Advances the enumerator to the next element of the collection. // // 返回结果: // true if the enumerator was successfully advanced to the next element; false if // the enumerator has passed the end of the collection. // // 异常: // T:System.InvalidOperationException: // The collection was modified after the enumerator was created. bool MoveNext(); // // 摘要: // Sets the enumerator to its initial position, which is before the first element // in the collection. // // 异常: // T:System.InvalidOperationException: // The collection was modified after the enumerator was created. void Reset(); } }
参考:
https://blog.csdn.net/ydm19891101/article/details/50969323