EF性能之關聯加載

魚和熊掌不能兼得html

——中國諺語sql

1、介紹

 Entity Framework做爲一個優秀的ORM框架,它使得操做數據庫就像操做內存中的數據同樣,可是這種抽象是有性能代價的,故魚和熊掌不能兼得。可是,經過對EF的學習,能夠避免沒必要要的性能損失。本篇只介紹關聯實體的加載的相關知識,這在我以前的文章中都有介紹。數據庫

咱們已經瞭解到EF的關聯實體加載有三種方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy LoadingExplicit Loading都是延遲加載。框架

(一)Lazy Loading使用的是動態代理,默認狀況下,若是POCO類知足如下兩個條件,EF就使用Lazy Loading:性能

  1. POCO類是Public且不爲Sealed
  2. 導航屬性標記爲Virtual

關閉Lazy Loading,能夠將LazyLoadingEnabled設爲false,若是導航屬性沒有標記爲virtual,Lazy Loading也是不起做用的。學習

(二)Eager Loading使用Include方法關聯預先加載的實體。spa

(三)Explicit Loading使用Entry方法,對於集合使用Collection,單個實體則使用Reference代理

2、實例

下面經過實例來理解這幾種加載方式。code

有下面三個實體:Province,City,Governor,一個Province有多個City,而且只有一個Governor。orm

   1:      public class Province
   2:      {
   3:          public int Id { get; set; }
   4:          public string Name { get; set; }
   5:   
   6:          public virtual Governor Governor { get; set; }
   7:   
   8:          public virtual List<City> Cities { get; set; }
   9:      }
  10:   
  11:      public class City
  12:      {
  13:          public int Id { get; set; }
  14:          public string Name { get; set; }
  15:      }
  16:   
  17:   
  18:      public class Governor
  19:      {
  20:          public int Id { get; set; }
  21:          public string Name { get; set; }
  22:      }

Lazy Loading

   1:          private static void LazyLoading(EFLoadingContext ctx)
   2:          {
   3:              //發送一條查詢到數據庫,查詢全部的province
   4:              var list = ctx.Provines.ToList();
   5:              foreach (var province in list)
   6:              {
   7:                  //每次遍歷(用到導航屬性時)都發送2條查詢,一條查詢當前province包含的city和另外一條查詢當前province的governor
   8:                  //若是ctx.Configuration.LazyLoadingEnabled爲false或者前者爲true,可是導航屬性沒有標註爲virtual,下面的操做都會拋出異常
   9:                  Print(province);
  10:              }
  11:          }

Eager Loading

   1:          private static void EagerLoading(EFLoadingContext ctx)
   2:          {
   3:              //發送一條查詢到數據庫庫,查詢全部的province並關聯city和governor
   4:              var list = ctx.Provines.Include(t => t.Cities).Include(t => t.Governor);
   5:              foreach (var province in list)
   6:              {
   7:                  //無論ctx.Configuration.LazyLoadingEnabled爲false,仍是沒有標註導航屬性virtual,都不會拋出異常
   8:                  Print(province);
   9:              }
  10:          }

Explicti Loading

   1:          private static void ExplicitLoading(EFLoadingContext ctx)
   2:          {
   3:              //發送一條查詢到數據庫,查詢全部的province
   4:              var list = ctx.Provines.ToList();
   5:              foreach (var province in list)
   6:              {
   7:                  var p = ctx.Entry(province);
   8:                  //發送一條查詢,查詢全部當前province的city
   9:                  p.Collection(t => t.Cities).Load();
  10:                  //發送一條查詢,查詢當前province的governor
  11:                  p.Reference(t => t.Governor).Load();
  12:                  //無論ctx.Configuration.LazyLoadingEnabled爲false,仍是沒有標註導航屬性virtual,都不會拋出異常
  13:                  Print(province);
  14:              }
  15:          }

Print方法

   1:          private static void Print(Province province)
   2:          {
   3:              Console.WriteLine("省:【{0}】,市:【{1}】,省長:【{2}】", province.Name, string.Join(",", province.Cities.Select(t => t.Name)), province.Governor.Name);
   4:          }

3、總結

關於關聯加載實體基本上就是這些內容吧,若是想看這部分詳細的介紹,能夠參考我這篇文章的後半部分。總的來講,這部分比較簡單,一個LazyLoadingEnabled設置,三種加載方式。Lazy Loading會生成大量的sql,Eager Loading生成的關聯查詢比較負責,Explicit Loading同Lazy Loading同樣生成不少的sql,可是有一些其餘優勢,好比:導航屬性能夠不用標註爲virtual。若是這幾種關聯都不能解決實際問題,能夠直接使用sql查詢。

最後附上本文的demo,下載地址:http://pan.baidu.com/s/1i3IAiNF

相關文章
相關標籤/搜索