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                 }
  • 相关阅读:
    通过PDB文件实现非嵌入式的c++反射
    在c++中实现反射的初步想法
    对比特币相关的一些技术细节的补充
    初窥比特币
    根据一个坐标查找其所属区域的一些优化想法
    go两种数据类型的区别、数据类型和操作符、常量、变量声明
    go的相关包time、os、rand、fmt
    go语言的特性
    结构体
    defer、panic、recover
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/7739685.html
Copyright © 2011-2022 走看看