第六節: 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                 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM