【EfF】 貪婪加載和延遲加載 (virtual去掉關閉延遲加載) EntityFramework(EF)貪婪加載和延遲加載的選擇和使用

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

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

當讀取訂單信息orders的時候,咱們但願把訂單的詳細信息也讀取出來,那麼這裏咱們使用Include關鍵字將關聯表也加載進 來。數據庫

 

延遲加載:即當咱們須要用到的時候才進行加載(讀取)緩存

當咱們但願瀏覽某條訂單信息的時候,才顯示其對應的訂單詳細記錄時,咱們但願使用延遲加載來實現,這樣不只加快的了 讀取的效率,同時也避免加載不須要的數據。延遲加載一般用於foreach循環讀取數據時。post

那麼咱們在定義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 }
複製代碼
複製代碼

 

 

總結:this

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

延遲加載: 一、只在須要讀取關聯數據的時候才進行加載 二、可能由於數據訪問的延遲而下降性能,由於循環中,每一條數據都會訪問一次數據庫,致使數據庫的壓力加大spa

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

一、若是是在foreach循環中加載數據,那麼使用延遲加載會比較好, 由於不須要一次性將全部數據讀取出來,這樣雖然有可能會形成n次數據庫的查詢,但 是基本上在能夠接受的範圍內。

二、若是在開發時就能夠預見須要一次性加載全部的數據,包含關聯表的全部數據, 那麼使用使用貪婪加載是比較好的選擇,可是此種方式會致使效率問題,特別是數據量大的狀況下。

兩張表:訂單表(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進行關聯。

 

 

 

 

相關文章
相關標籤/搜索