IQuerable与IEnumable的区别
Posted hao_1234_1234
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IQuerable与IEnumable的区别相关的知识,希望对你有一定的参考价值。
核心区别:
IQueryable该接口会把查询表达式先缓存到表达式树Expression 中,只有当真正遍历发生的时候,才会由IQueryProvider解析表达式树,生成sql语句执行数据库查询操作。(离线集合)
IEnumable 该接口会立即返回需要的集合。(本地集合)
IQueryable接口(F12查看)
namespace System.Linq { public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } } }
案例一:
先上代码
- 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接口。
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
以上是关于IQuerable与IEnumable的区别的主要内容,如果未能解决你的问题,请参考以下文章
IQueryableIEnumberable IList与List区别
csharp IQuerable ToSqlString扩展方法。来自https://www.stevefenton.co.uk/2015/07/getting-the-sql-query-from-