zoukankan      html  css  js  c++  java
  • 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)

    一. 简介

       上一个章节中,也介绍了立即加载和延迟加载,但上一个章节是针对单表而言的,不含外键,立即也好,延迟也好,都是指单表中的数据。但本章节重点介绍的三种加载方式均是针对含(导航属性、外键)的情况下,查询主表,从表中的数据加载情况。

      下面准备两张表:Student和StudentAddress两张表,一对一 or 零 的关系,实体结构如下,通过CodeFirst来反向生成数据库。

     1     /// <summary>
     2     /// 学生表(一个学生只能有一个地址或没有地址)
     3     /// </summary>
     4     public class Student
     5     {
     6         public Student()
     7         {
     8 
     9         }
    10         public string studentId { get; set; }
    11 
    12         public string studentName { get; set; }
    13 
    14 
    15         public virtual StudentAddress StudentAddress { get; set; }
    16     }
     1     /// <summary>
     2     /// 学生地址表(一个地址只能对应一个学生)
     3     /// </summary>
     4     public class StudentAddress
     5     {
     6         public StudentAddress()
     7         {
     8 
     9         }
    10 
    11         [ForeignKey("stu")]
    12         //特别注意这个地方,stu对应下面的 Student stu;  
    13         //另外特别注意:studentAddressId,符合默认的Id生成规则,自动映射成主键,否则需要加【key】特性
    14         public string studentAddressId { get; set; }   
    15 
    16         public string addressName { get; set; }
    17 
    18         public virtual Student stu { get; set; }
    19     }

    二. Lazy Loading

     1. 又名:延迟加载、懒加载

     2. 需要满足的条件:

       ①:poco类是public且不能为sealed

       ②:导航属性需要标记为Virtual

       满足以上两个条件,EF6默认就为延迟加载的模式。(默认:db.Configuration.LazyLoadingEnabled = true; )

    3. 含义:每次调用子实体(外键所在的实体)的时候,才去查询数据库. 主表数据加载的时候,不去查询外键所在的从表。

    4. 关闭延迟加载的办法: db.Configuration.LazyLoadingEnabled = false;

      特别注意:关闭延迟加载后,查询主表数据时候,主表的中从表实体为null.

    1. 延迟加载代码测试

     1                 using (dbContext1 db = new dbContext1())
     2                 {
     3                     Console.WriteLine("--------------------------- 01-延迟加载 -----------------------------");
     4                     db.Database.Log = Console.WriteLine;
     5 
     6                     //EF默认就是延迟加载,默认下面的语句就是true,所以下面语句注释没有任何影响
     7                     //db.Configuration.LazyLoadingEnabled = true;
     8 
     9                     var list = db.Student.ToList();  //此处加载的数据,根据监测得出结论,没有对从表进行任何查询操作
    10                     foreach (var stu in list)
    11                     {
    12                         Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName);
    13 
    14                         //下面调用导航属性(一对一的关系)  每次调用时,都要去查询数据库(查询从表)
    15                         var stuAddress = stu.StudentAddress;
    16                         Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName);
    17                     }
    18                 }

    2. 关闭延迟加载

     1                 using (dbContext1 db = new dbContext1())
     2                 {
     3                     try
     4                     {
     5                         Console.WriteLine("--------------------------- 02-关闭延迟加载 -----------------------------");
     6                         db.Database.Log = Console.WriteLine;
     7 
     8                         //下面的语句为关闭延迟加载
     9                         db.Configuration.LazyLoadingEnabled = false;
    10 
    11                         var list = db.Student.ToList();  //关闭延迟加载后,此处从表实体StudentAddress为null,后面不会再次查询了
    12                         foreach (var stu in list)
    13                         {
    14                             Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName);
    15 
    16                             //StudentAddress为null,不会再次查询数据库,所以此处报错
    17                             var stuAddress = stu.StudentAddress;
    18                             Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName);
    19                         }
    20                     }
    21                     catch (Exception ex)
    22                     {
    23                         Console.WriteLine(ex.Message);
    24                     }
    25                 }

    三. Eager Loading

     1. 又名:立即加载、贪婪加载、预加载

     2. 使用步骤:

       ①:先关闭延迟加载:db.Configuration.LazyLoadingEnabled = false;

       ②:查询主表的同时通过Include把从表数据也查询出来:

     3. 含义:由于查询主表的时候通过Include已经一次性将数据查询了出来,所以在调用从表数据的时候,均从缓存中读取,无须查询数据库

    代码测试

     1           using (dbContext1 db = new dbContext1())
     2                 {
     3                     Console.WriteLine("--------------------------- 03-立即加载 -----------------------------");
     4                     db.Database.Log = Console.WriteLine;
     5 
     6                     //1.关闭延迟加载
     7                     db.Configuration.LazyLoadingEnabled = false;
     8 
     9                     //2. 获取主表数据的同时,通过Include将从表中的数据也全部加载出来
    10                     var list = db.Student.Include("StudentAddress").ToList();
    11                     foreach (var stu in list)
    12                     {
    13                         Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName);
    14 
    15                         //这里获取从表中的数据,均是从缓存中获取,无需查询数据库
    16                         var stuAddress = stu.StudentAddress;
    17                         Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName);
    18                     }
    19 
    20                 }

    四. Explicit Loading

     1. 又名:显示加载

     2. 背景:关闭延迟加载后,单纯查询主表的数据,后面又想再次查询从表,这个时候就需要用到显示加载了.

     3. 前提:

       ①:关闭了延迟加载:db.Configuration.LazyLoadingEnabled = false;

       ②:单纯查询了主表,没有使用Include函数关联查询从表.

     4. 使用步骤:

       ①:单个实体用:Reference

       ②:集合用:Collection

       ③:最后需要Load一下

     5. 含义:关闭了延迟加载,单纯查询了主表数据,这个时候需要重新查询从表数据,就要用到显式加载了

    代码测试

     1          using (dbContext1 db = new dbContext1())
     2                 {
     3                     Console.WriteLine("--------------------------- 04-显式加载 -----------------------------");
     4                     db.Database.Log = Console.WriteLine;
     5 
     6                     //1.关闭延迟加载
     7                     db.Configuration.LazyLoadingEnabled = false;
     8 
     9                     //2.此处加载的数据,不含从表中的数据
    10                     var list = db.Student.ToList();
    11                     foreach (var stu in list)
    12                     {
    13                         Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName);
    14 
    15                         //3.下面的这句话,可以开启重新查询一次数据库
    16                         //3.1 单个属性的情况用Refercence
    17                         db.Entry<Student>(stu).Reference(c => c.StudentAddress).Load();
    18                         //3.2 集合的情况用Collection
    19                         //db.Entry<Student>(stu).Collection(c => c.StudentAddress).Load();
    20 
    21                         //下面调用导航属性(一对一的关系)  每次调用时,都要去查询数据库
    22                         var stuAddress = stu.StudentAddress;
    23                         Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName);
    24                     }
    25 
    26                 }
  • 相关阅读:
    三次请求(读-改-读)引出nibernate 一级缓存
    算法竞赛入门经典第一、二章摘记
    uva 10905 Children's Game
    uva 11205 The broken pedometer
    uva 10160 Servicing stations
    uva 208 Firetruck
    uva 167 The Sultan's Successors
    zoj 1016 Parencodings
    uva 307 Sticks
    uva 216 Getting in Line
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/7739685.html
Copyright © 2011-2022 走看看