博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linq之延迟加载特性
阅读量:6039 次
发布时间:2019-06-20

本文共 3432 字,大约阅读时间需要 11 分钟。

目录

写在前面

上篇文章介绍了linq中常见的几个关键字,并列举了几个例子,算是对linq如何使用有了初步了解。上篇文章中也提到了,能够使用linq的场合有一个要求:实现IEnumerable<T>泛型接口,或者类型兼容(可以通过Cast方法转换,比如ArrayList)。

系列文章

延迟加载

延迟加载在很多orm框架中都有支持,什么是延迟加载?通俗一点,就是你需要的时候再去查询,不需要的时候就不查询。

Linq查询的执行结果是IEnumerable<T>类型,而对IEnumerable<T>,在内部,C#通过yield关键字实现迭代器达到延迟加载的目的。从而使Linq查询只是在需要的时候才会被执行。

下面看一个例子

1 namespace Wolfy.LinqLazyLoad 2 { 3     class Program 4     { 5         static void Main(string[] args) 6         { 7             List
persons = new List
() { 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 persons17 .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)23 {24 Console.WriteLine(item.ToString());25 }26 Console.Read();27 }28 }29 class Person30 {31 public int ID { set; get; }32 public string Name { set; get; }33 public int Age { set; get; }34 public override string ToString()35 {36 return ID + " " + Name + " " + Age;37 }38 }39 }

例子很简单,通过linq查询,按年龄降序输出。

看一下输出结果

通过这点也许你可能还不是很清楚。

那么我们再举一个linq立即加载的例子,对比一下

1   static void Main(string[] args) 2         { 3             List
persons = new List
() { 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 persons13 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 }

输出结果

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://zjrhx.baihongyu.com/

你可能感兴趣的文章
csv文件的操作
查看>>
基本调试命令 - u/ub/uf
查看>>
实现锁的多种方式和锁的高级用法
查看>>
C语言-一个fopen函数中未使用二进制模式(b)引发的血案
查看>>
Codeforces Round #260 (Div. 1) C. Civilization 并查集,直径
查看>>
Objective-C中常用的结构体NSRange,NSPoint,NSSize(CGSize),NSRect
查看>>
关于spark standalone模式下的executor问题
查看>>
TC SRM 664 div2 B BearPlaysDiv2 bfs
查看>>
Retrofit全攻略——基础篇
查看>>
代理模式
查看>>
具体问题具体分析
查看>>
【SqlServer系列】表达式(expression)
查看>>
maven与gradle的对比
查看>>
异常备忘:java.lang.UnsupportedClassVersionError: Bad version number in .class file
查看>>
uasy-datetimebox的使用
查看>>
Android Home键监听
查看>>
Java JVM虚拟机选项Xms/Xmx/PermSize/MaxPermSize(转)
查看>>
linux convert命令安装及使用
查看>>
JavaWeb(一)Servlet中乱码解决与转发和重定向的区别
查看>>
laravel5.5 Syntax error or access violation: 1071 Specified key was too long
查看>>