zoukankan      html  css  js  c++  java
  • Linq之延迟加载特性

    目录

    写在前面

    系列文章

    延迟加载

    总结

    写在前面

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

    系列文章

    Linq之Lambda表达式初步认识

    Linq之Lambda进阶

    Linq之隐式类型、自动属性、初始化器、匿名类

    Linq之扩展方法

    Linq之Expression初见

    Linq之Expression进阶

    Linq之Expression高级篇(常用表达式类型)

    Linq之常见关键字

    延迟加载

    延迟加载在很多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<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)
    23             {
    24                 Console.WriteLine(item.ToString());
    25             }
    26             Console.Read();
    27         }
    28     }
    29     class Person
    30     {
    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<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         }

    输出结果

    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/

  • 相关阅读:
    如何配置wamp多站点主机
    一些类和对象问题的探索,简单易懂的命名空间及use的使用
    [4] Git使用流程
    [正则] JS常用正则
    [3] Django返回json数据
    [8] Eclipse各版本代号一览表以及官网上有很多版本的eclipse的比较
    [7] MySQL数据库--学生管理系统数据库设计
    [11]Docker02 Docker重要概念
    [12]Docker03 Centos7安装Docker
    [小程序]小程序环境搭建
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/4273210.html
Copyright © 2011-2022 走看看