1. 程式人生 > >讀取關聯資料(EF Core2.1.1)

讀取關聯資料(EF Core2.1.1)

物件-關係對映框架比如EF有三種 方式使用 模型中的導航屬性來載入關聯資料。

一、.Lazy Loading.(關聯資料在訪問導航屬性時被透明的載入,不需要特別的程式碼,自動的載入)

當一個實體第一次讀取的時候,關聯資料不會被檢索。然後,當你第一次訪問這個實體的導航屬性的時候,導航屬性需要的資料自動的被檢索。每當你第一次從導航屬性獲取資料時,都會向資料庫傳送查詢。這樣,會導致多個查詢被髮送到資料庫。一個是實體本身,另外,每當實體的關聯資料第一次被訪問的時候。EF6.x的DbContext類預設啟用了Lazy loading.

lazy loading 不支援AsNoTracking()方法,使用了.AsNoTracking(),lazy loading會發生異常。

而EF Core1的版本是不支援Lzay Loading的。從EF2.1.開始支援Lazy Loading,但必須是可以覆寫的導航屬性,也就是 說定義為虛 virtual屬性,和能夠被繼承的。需要進行以下設定。

1、安裝代理類

PMC:Install-Package Microsoft.EntityFrameworkCore.Proxies -Version 2.1.1

在Startup.cs配置檔案中,ConfigureService方法中,

//啟動檔案,在依賴注入容器中註冊資料庫上下文物件。
2、services.AddDbContext<SchoolContext>(options =>
options.UseLazyLoadingProxies().

UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); //如果未在Context中新增UseLazyLoadingProxies,導航屬性不會新增。

departments =context.Departments;

foreach(Department d in departments)

{

 foreach(Course c in d.Courses)

{

   courseLIst.Add(d.Name + c.title)

}

}

二、EagerLoading  (關聯資料在初始的查詢裡面就從資料庫載入)

當實體第一次被讀取的時候,關聯的資料一起被檢索。這將會導致僅有的連線查詢會檢索所有需要的全部資料。通過EF core使用Include方法和ThenInclude方法來指定eagerLoding.

departments =context.Departments.Include(x =>x.Course) //一條語句就從資料庫中載入所有的關聯屬性。

foreach(Department d in departments)

{

 foreach(Course c in d.Courses)

{

  courseList.Add(d.Name +c.Title);

}

}

三、Explicit loading (關聯資料後來才能被顯式的從資料庫載入)

1.這個與lazy loading相似,除了需要顯式的使用程式碼來檢索關聯資料。當你訪問一個導航屬性的時候,不會自動發生。需要通過物件狀態管理器(object state manager)Entry手動的載入關聯資料,,呼叫Collection.Load(導航屬性為集合)方法和reference.Load(導航屬性為單個實體)方法。你使用顯式載入僅僅是關閉了lazy loading。

departments =context.Departments.Tolist();

foreach(Department d in departments)

{

 context.Entry(d).Collection(d =>d.Courses).Load(); //用Entry load()程式碼明確從資料庫載入關聯資料。

 foreach(Course c in d.Courses)

{

  courseList.Add(d.Name +c.Title);

}

}

2.你能夠使用單獨的查詢來檢索資料,EF會 修復導航屬性。也就是說EF自動地將它們所屬的單獨檢索的實體新增到先前檢索實體集的導航屬性中。對於檢索相關資料的查詢,可使用Load方法而不是返回列表或物件的方法,例如:ToList()或者 Single()

departments =context.Departments.Include(x =>x.Courses)

foreach(Department d in departments)

{

  context.Courses.Where(c =>c.DepartmentID == d.DepartmentId).Load(); //從資料庫中載入實體的導航屬性,使用load();

foreach(Course c in d.Courses) // 由於EF  Core修復了導航屬性,因此,這裡不是lazy loading,而是eager loading.

{

courseList.Add(d.Name +c.Title)

}

}

因為lazy loading和explicit loading不會立即查詢屬性值,因為它們都屬於延遲載入(deferred loading).

效能考慮

如果每一個實體的導航屬性都需要被查詢,eager  loading通常能提供最好的效能,因為只有一個查詢被髮送到資料庫,比起檢索單個實體的獨立的查詢,減少了對資料庫訪問來回的次數,顯得更加高效。

另一方面,在一些情況下,Lazy loading更加高效。Eager loading可能導致非常複雜的連線查詢,SQL伺服器不能有效的處理。如果你僅僅需要訪問一個實體集的其中一部分(子集)實體的導航屬性,則延遲載入可能會執行得更好,因為預先載入將檢索比您需要的更多資料。 如果效能至關重要,最好以兩種方式測試效能,以便做出最佳選擇。

延遲載入可以掩蓋導致效能問題的程式碼。例如,處理大量的實體,並且在每次迭代中使用了多個導航屬性,沒有指定eager loading或explicit loading ,這樣的程式碼執行效率非常低。因為多次往返資料庫。一個應用程式在本地開發過程中執行良好,但當移植到Azure SQL資料庫時,由於延遲增加和Lazying loading可能出現效能問題。

序列化 的時候使用lazy loading將導致失控的鏈式反應,序列化之前要關閉lazy loading.