一. 本地緩存
從這個章節開始,介紹一下EF的一些高級特性,這里介紹的首先介紹的EF的本地緩存,在前面的“EF增刪改”章節中介紹過該特性(SaveChanges一次性會作用於本地緩存中所有的狀態的變化),在這里介紹一下本地緩存的另外一個用途。
① Find方法通過主鍵查詢數據,主鍵相同的查詢,只有第一次訪問數據庫,其它均從緩存中讀取。
② 延遲加載的數據,在第一次使用的使用時訪問數據庫,后面無論再使用多少次,均是從內存中讀取了。
1 Console.WriteLine("--------------------------- 1.本地緩存屬性 ------------------------------------"); 2 db.Database.Log += c => Console.WriteLine(c); 3 //以下4個根據主鍵id查詢,查詢了一次,都存到本地緩存里了,所以user2不查詢數據庫,但user3的id不同,所以查詢數據庫 4 var user1 = db.Set<TestInfor>().Find("2"); 5 var user2 = db.Set<TestInfor>().Find("2"); 6 var user3 = db.Set<TestInfor>().Find("3");
二. 立即加載
這里的立即加載指單表,不含主外鍵的情況。
所謂的立即加載就是代碼執行的時候直接去數據庫查詢,與是否立即使用無關,查出來后放到本地緩存里,以后再次使用的時候,從本地緩存中讀取。
常見的立即加載的的標記:toList() 、FirstOrDefault() 。
1 Console.WriteLine("--------------------------- 2.即時加載 ------------------------------------"); 2 3 ////以下3個屬於立即查詢,所以每次都要查詢數據庫,不緩存 4 var user5 = db.Set<TestInfor>().Where(u => u.id == "2").FirstOrDefault(); 5 var user6 = db.Set<TestInfor>().Where(u => u.id == "2").FirstOrDefault(); 6 var user7 = db.Set<TestInfor>().Where(u => u.id == "2").FirstOrDefault();
三. 延遲加載
這里的延遲加載指單表,不含主外鍵的情況。
1. 定義:只有我們需要數據的時候,才去數據庫查詢
比如:我們需要根據條件判斷,通過Where來拼接條件(IQueryable),在拼接的過程中,並沒有訪問數據庫,只有在最終使用的時候,才訪問數據庫。
特別注意:調用的時候要foreach循環來調用,只有第一次使用的時候去訪問數據庫,其它的都是從本地緩存中讀取。
2. 禁用延遲加載的方法:
a:如果結果是集合,在拼接的結尾加 toList() ,其它類型調用其它方法
b:如果結果是單個實體,在拼接的結尾加 FirstOrDefault()
3. 好處:保證了數據的實時性,什么時候用,什么時候查詢
4. 弊端:每用一次,就需要查詢一次數據,服務器壓力大
5. 延遲加載的實際開發場景:
分頁要要經歷where多個條件查詢、skip、take、toList,如果每調用一個方法都連接一個數據庫,那么在拼接過程中就訪問了3次數據庫,而且可能數據量非常多,所以這個時候使用延遲加載,只有在所有sql語句拼接完的最后一步才連接數據庫。
總結:只要查詢結果實現了IQueryable接口類的,那么查詢結果都是延遲加載的。
1 Console.WriteLine("--------------------------- 3.延遲加載 ------------------------------------"); 2 IQueryable<TestInfor> user4 = db.Set<TestInfor>().Where(u => u.id != "123"); 3 IQueryable<TestInfor> user6 = db.Set<TestInfor>().Where(u => u.id != "123"); 4 foreach (var item in user4) 5 { 6 Console.WriteLine("我要從數據庫中讀取數據了:" + item.txt1); 7 } 8 foreach (var item in user4) 9 { 10 Console.WriteLine("我要從數據庫中讀取數據了2:" + item.txt1); 11 } 12 foreach (var item in user6) 13 { 14 Console.WriteLine("我要從數據庫中讀取數據了3:" + item.txt1); 15 }
延遲加載上述案例分析:
* IQueryable類型的 user4和user6, 都是延遲加載的,下面foreach第一次使用該對象的時候去數據庫查詢。
* 這里會有這么幾個問題:
* ①:foreach第一次遍歷的時候去數據庫中查詢user4,然后放到本地緩存里,后面無論循環多少次,都是從本地緩存中讀取user4。
* ②:前兩個foreach操控的對象都是user4,所以第二個foreach無論哪次循環,都是從本地緩存中讀取
* ③:第三個foreach操控的對象是user6,同樣是在foreach第一次循環的時候去數據庫查詢,所以在代碼執行到第一個或第二個foreach的時候,
* 手動去數據庫改數據,當執行到第三個foreach,查詢出來的數據就是修改后的了。