Linq之延迟加载特性
上篇文章介绍了linq中常见的几个关键字,并列举了几个例子,算是对linq如何使用有了初步了解。上篇文章中也提到了,能够使用linq的场合有一个要求:实现IEnumerable T 泛型接口,或者类型兼容(可以通过Cast方法转换,比如ArrayList)。
延迟加载在很多orm框架中都有支持,什么是延迟加载?通俗一点,就是你需要的时候再去查询,不需要的时候就不查询。
Linq查询的执行结果是IEnumerable T 类型,而对IEnumerable T ,在内部,C#通过yield关键字实现迭代器达到延迟加载的目的。从而使Linq查询只是在需要的时候才会被执行。
下面看一个例子
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 namespace Wolfy.LinqLazyLoad 3 class Program 5 static void Main(string[] args) 7 List Person persons = new List Person () { 8 new Person(){ ID=1,Name="wolfy1", Age=1}, 9 new Person(){ ID=2,Name="wolfy2", Age=2}, 10 new Person(){ ID=3,Name="wolfy3", Age=3}, 11 new Person(){ ID=4,Name="wolfy4", Age=4}, 12 new Person(){ ID=5,Name="wolfy5", Age=5}, 13 new Person(){ ID=6,Name="wolfy6", Age=6} 14 }; 15 //这里使用linq进行查询 16 var query = from p in persons 17 .OrderByDescending(p = p.Age) 18 select new { p.ID, p.Name, p.Age }; 19 //如果是linq是延迟加载的,则输出的结果就应该是修改后的(延迟加载,说明query中此时并没有实际加载数据) 20 //如果linq立即加载的,则此时query中就相当于一个临时的缓冲区,数据已经存在了query中,就算对persons中某一项修改并不影响query中的数据。 21 persons[2] = new Person() { ID = 7, Name = "zhangsan", Age = 7 }; 22 foreach (var item in query) 24 Console.WriteLine(item.ToString()); 26 Console.Read(); 29 class Person 31 public int ID { set; get; } 32 public string Name { set; get; } 33 public int Age { set; get; } 34 public override string ToString() 36 return ID + " " + Name + " " + Age; 39 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
例子很简单,通过linq查询,按年龄降序输出。
看一下输出结果
通过这点也许你可能还不是很清楚。
那么我们再举一个linq立即加载的例子,对比一下
![复制代码](http://common.cnblogs.com/images/copycode.gif)
1 static void Main(string[] args) 3 List Person persons = new List Person () { 4 new Person(){ ID=1,Name="wolfy1", Age=1}, 5 new Person(){ ID=2,Name="wolfy2", Age=2}, 6 new Person(){ ID=3,Name="wolfy3", Age=3}, 7 new Person(){ ID=4,Name="wolfy4", Age=4}, 8 new Person(){ ID=5,Name="wolfy5", Age=5}, 9 new Person(){ ID=6,Name="wolfy6", Age=6} 10 }; 11 //使用聚合函数年龄总和 12 var result = (from p in persons 13 select p.Age) 14 .Sum(); 15 //如果是linq是延迟加载的,则输出的结果就应该是修改后的(延迟加载,说明query中此时并没有实际加载数据) 16 //如果linq立即加载的,则此时query中就相当于一个临时的缓冲区,数据已经存在了query中,就算对persons中某一项修改并不影响query中的数据。 17 persons[2] = new Person() { ID = 7, Name = "zhangsan", Age = 7 }; 18 Console.WriteLine("Sum " + result); 19 Console.Read(); 20 }
![复制代码](http://common.cnblogs.com/images/copycode.gif)
输出结果
21=1+2+3+4+5+6。这里也说明一个问题,在linq中,一些聚合函数例如Sum,求平均值等操作会影响linq的延迟加载特性。
上面的第一个例子是延迟加载,在query中并没有加载数据,然后你修改了persons[2]的值,你再输出query中的每一个值的时候,此时才是真正的加载数据,而此时加载数据,persons[2]的值已经发生变化了,所以会输出最新的persons[2]。
第二个例子中,聚合函数为什么会影响延迟加载特性呢,其实也很好理解,比如在该例子中进行求和运算,求和运算就需要所有的值,所以就需要先将值查询出来,然后才能求和,此时已经将结果保存在了result中,就算你下面再修改persons[2]的值,也没有用了。
通过上面的例子,以及Linq查询的执行结果是IEnumerable T 类型,而对IEnumerable T ,在内部,C#通过yield关键字实现迭代器达到延迟加载的目的。从而使Linq查询只是在需要的时候才会被执行,可以得到这样的结论:
1、可以自定义一个类实现泛型接口IEnumerable T ,在迭代器块中通过yield关键字,可以实现延迟加载的目的。
2、linq中使用聚合函数,将会强制查询,将强制进行立即加载。
上面的例子,有点绕,各种缘由,需慢慢体会。
思考:为什么yield关键字就能实现延迟加载的特性呢?(查找很多资料,未果)
参考文章
http://kb.cnblogs.com/page/100043/
博客版权: 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。
如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步!
再次感谢您耐心的读完本篇文章。http://www.cnblogs.com/wolf-sun/p/4273210.html
相关文章
- unity3d格式的导出与加载
- 用tableView实现的一种加载数据的布局
- 类的加载到反射reflect
- 【C#】Excel导出合并行和列并动态加载行与列
- 设置窗体的加载位置
- 页面中引入seajs以及模块的加载和启动
- knockoutjs如何动态加载外部的file作为component中的template数据源
- 【网址收藏】dubbo特新概念及特性、环境搭建、dubbo-monitor安装、rpc原理以及dubbo原理:框架设计、启动解析&加载配置信息、服务暴露、服务引用及调用
- 第4期ThreadX视频教程:单片机动态APP加载玩法,像手机电脑一样加载卸载多个应用软件(2022-05-01)
- openlayer3 加载geoserver发布的WFS服务
- SAP 电商云 Spartacus UI 模块延迟加载的入口程序
- JavaScript 模块的循环加载
- mybatis的statement的解析与加载(springboot)
- android 10.0 更换壁纸加载慢滑动卡顿的解决
- 【QML 动态对象】Loader动态加载组件
- Spring读书笔记——bean加载
- leaflet使用circle加载显示多个点(示例代码040)
- TensorFlow加载模型时出错
- arthas类和类加载器相关命令:dump、classloader