EntityFramework(EF)貪婪加載和延遲加載的選擇和使用


貪婪加載:顧名思議就是把所有要加載的東西一 次性讀取

1 using (var context = new MyDbContext()) 2 { 3 var orders = from o in context.Orders.Include("OrderDetails") select o; 4 }

當讀取訂單信息orders的時候,我們希望把訂單的詳細信息也讀取出來,那么這里我們使用Include關鍵字將關聯表也加載進 來。

 

延遲加載:即當我們需要用到的時候才進行加載(讀取)

當我們希望瀏覽某條訂單信息的時候,才顯示其對應的訂單詳細記錄時,我們希望使用延遲加載來實現,這樣不僅加快的了 讀取的效率,同時也避免加載不需要的數據。延遲加載通常用於foreach循環讀取數據時。

那么我們在定義Model的時候,需要在屬性前面添加virtual關鍵字。如下

復制代碼
1 public class Order 2 { 3 public int OrderID { get; set; } 4 public string OrderTitle { get; set; } 5 public string CustomerName { get; set; } 6 public DateTime TransactionDate { get; set; } 7 public virtual List<OrderDetail> OrderDetails { get; set; } 8 } 
復制代碼

 

如果我們想要禁止使用延遲加載,那么最好的方法是在DbContext類的構造方法中聲明

復制代碼
1 public class MyDbContext:DbContext 2 { 3 public MyDbContext() 4  { 5 this.Configuration.LazyLoadingEnabled = false; 6  } 7 }
復制代碼

 

 

總結:

貪婪加載: 1、減少數據訪問的延遲,在一次數據庫的訪問中返回所有的數據。 2、一次性讀取所有相關的數據,可能導致部分數據實際無需用到,從而導致讀取數據的速度變慢,效率變低

延遲加載: 1、只在需要讀取關聯數據的時候才進行加載 2、可能因為數據訪問的延遲而降低性能,因為循環中,每一條數據都會訪問一次數據庫,導致數據庫的壓力加大

綜上所述,我們應該比較清楚時候應該使用哪種機制?我個人的建議是:

1、如果是在foreach循環中加載數據,那么使用延遲加載會比較好, 因為不需要一次性將所有數據讀取出來,這樣雖然有可能會造成n次數據庫的查詢,但 是基本上在可以接受的范圍內。

2、如果在開發時就可以預見需要一次性加載所有的數據,包含關聯表的所有數據, 那么使用使用貪婪加載是比較好的選擇,但是此種方式會導致效率問題,特別是數據量大的情況下。

兩張表:訂單表(Order_Info)和產品表(Order_Detail

         訂單表:包含2條訂單

         產品表:4件產品,分別屬於上面兩個訂單

 

優化一  

  問題:查詢每件產品屬於哪個訂單時,需要連接幾次數據庫?

     本應該查詢4次,EF做了優化后,查詢2次。

 

  1.  public static void QueryUser()  
  2. {   
  3.         IQueryable<Order_Detail>query = db.Order_Detail.Where(a => a.OrderID>0);  
  4.   
  5.         foreach (Order_Detail detail inquery)  
  6.         {  
  7.             Console.WriteLine("產品" + detail.ProductName  
  8.              + ",所屬訂單" + detail.Order_Info.OrderID);  
  9.         }  
  10. }  
     public static void QueryUser()
    { 
            IQueryable<Order_Detail>query = db.Order_Detail.Where(a => a.OrderID>0);
 
            foreach (Order_Detail detail inquery)
            {
                Console.WriteLine("產品" + detail.ProductName
                 + ",所屬訂單" + detail.Order_Info.OrderID);
            }
    }
    

 

 

 

 

   為什么查詢了2次?

   當他發現4條產品的訂單號有重復的時候,他就讀取他自己的緩存數據,就不讀取數據庫里面的數據里,這是EF做的一個小優化。

        

優化二  include進行inner join查詢

    雖然EF為我們做了優化一,那當我們有1000個產品時,即使讀取又重復的產品,那也需要去讀1000次。之前我們只需要一個inner join就可以一次性讀取出來。

 

  1. //這里的include需要加載的文字,是從 Orderil_Detail的表結構里面訂單的屬性名字來復制的,注意是屬性名字,而不是屬性的類  
  2.  IQueryable<Order_Detail>query = db.Order_Detail.Include("Order_Info").Where(a =>a.OrderID>0);  
  3.   
  4.  foreach (Order_Detail detail inquery)  
  5.  {  
  6.      Console.WriteLine("產品" + detail.ProductName  
  7.       + ",所屬訂單" + detail.Order_Info.OrderID);  
  8.  }  
           //這里的include需要加載的文字,是從 Orderil_Detail的表結構里面訂單的屬性名字來復制的,注意是屬性名字,而不是屬性的類
            IQueryable<Order_Detail>query = db.Order_Detail.Include("Order_Info").Where(a =>a.OrderID>0);
 
            foreach (Order_Detail detail inquery)
            {
                Console.WriteLine("產品" + detail.ProductName
                 + ",所屬訂單" + detail.Order_Info.OrderID);
            }

 

 

         

    通過使用include,我們可以實現查詢一次數據庫即可,相當於之前的inner join。如果關聯多個表,可以使用多個include進行關聯。

 

 


免責聲明!

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



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