延遲載入又稱懶載入,通俗一點就是關聯了一個物件,不用的時候不去查這個物件,當呼叫的時候再組織sql去查出這個物件的相關內容。
一.在使用EF時,我們會發現藉助於框架生成的實體類中的的導航屬性通常是標記 virtual的,這是為何呢?
二.讓我們通過幾個例子來發現其中的奧祕
下面的程式碼是通用的查詢,先是列印了查詢生成的sql,接著查詢出一個Employee物件並帶出對應的Dempartment物件。
using (DemoEntities db = new DemoEntities()) { db.Database.Log = sql => Console.WriteLine(sql); Employee emp = db.Employees.FirstOrDefault(); Console.WriteLine(emp.Name); Console.WriteLine(emp.Department.Name); }
1.導航屬性上有virtual的情況下查詢兩條sql,一條是查出Employee另一條是查Dempartment
2.現在我們將預設的導航屬性中的virtual去掉會發生什麼呢,讓我們帶著疑惑繼續往下看
三.原理探究
看到這是不是感覺很怪異嘍,加上virtual就能正常執行,去掉就不行了麼。這是啥原理呢
1.我們把程式碼修改一下
using (DemoEntities db = new DemoEntities()) { Employee emp = db.Employees.FirstOrDefault(); Console.WriteLine(emp.GetType()); //列印emp的型別 Console.WriteLine(emp.GetType().BaseType); //列印emp型別對應的父類 Console.WriteLine(emp.Name); Console.WriteLine(emp.Department.Name); }
在原有的基礎上我們列印了一下對應物件的型別
2.我們還是先看看預設有virtual的情況
通過執行程式碼我們發現,我們所宣告的Employee的物件的型別竟然不是Employee而是一個名字特別長的另一個物件,而這個物件的父類才是Employee
3.我們將導航屬性的virtual去掉再執行程式碼看看有什麼變化
看到這裡的差異,我們似乎發現了點什麼。先說說virtual關鍵字吧,virtual是虛方法,通常是用於子類的重寫。那麼這裡我們不難推測當導航屬性有virtual關鍵字時,EF幫我們生成了一個
父類是Employee名字老長老長的那個類,在這個類的實現中,重寫了一下,當Department為空時,它會去資料庫裡查一下這個Department物件,所以加上virtual關鍵字時就會對應兩條sql
類似效果如下所示
class Employee_515EB7DF3C6168BFE9566BD863543E3AED9398AFF473BAB129D9B32823D6E8A3 : Employee { private Department _department; public override Department Department { get { if (_department==null) { //去資料庫中查詢Department的資訊 } return _department; } } }