Entity Framework提供了三種載入相關實體的方法:Lazy Loading,Eager Loading和Explicit Loading。首先我們先來看一下MSDN對三種載入實體方法的定義。
Lazy Loading:對於這種類型的載入,在您訪問導覽屬性時,會從資料來源自動載入相關實體。 使用此載入類型時,請注意,如果實體尚未在 ObjectContext 中,則您訪問的每個導覽屬性都會導致針對資料來源執行一個單獨的查詢。
Eager Loading:當您瞭解應用程式需要的相關實體的圖形的確切形狀時,可以使用 ObjectQuery 的 Include 方法來定義查詢路徑,此查詢路徑控制將哪些相關實體作為初始查詢的一部分返回。 當定義查詢路徑時,僅需對資料庫請求一次,即可在單個結果集中返回查詢路徑所定義的所有實體,並且屬於在路徑中定義的類型的所有相關實體將隨查詢返回的每個對象一起載入。
Explicit Loading:將實體明確式載入到 ObjectContext 需要多次往返資料庫,並且可能需要多個活動結果集,但是返回的資料量僅限於所載入的實體。 可以對 EntityCollection或 EntityReference 使用 Load 方法或對 ObjectContext 使用 LoadProperty 方法,以便從資料來源顯式檢索相關實體。 對於 Load 方法的每個調用都會開啟與資料庫的串連,以檢索相關資訊。 這可確保在沒有對相關實體的顯式請求時,始終不會執行查詢。
下面我們就以上三種載入方式來一一進行測試
在測試之前,我們先建立一個測試用的資料庫,並在其中插入一些資料:
圖1
Lazy Loading
在Entity Framework4.0及其以後版本,LazyLoading是預設開啟的,從資料庫產生Model後,我們可以在EDMX檔案空白處單擊,並在屬性視窗看到這一設定:
圖2
也可以以XML形式開啟EDMX檔案,在CSDL部分看到這一設定:
View Code
1 <!-- CSDL content -->
2 <edmx:ConceptualModels>
3 <Schema Namespace="TestModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
4 <EntityContainer Name="TestEntities" annotation:LazyLoadingEnabled="true">
5 <EntitySet Name="Players" EntityType="TestModel.Player" />
6 <EntitySet Name="PlayerDetails" EntityType="TestModel.PlayerDetail" />
7 <EntitySet Name="Teams" EntityType="TestModel.Team" />
8 <AssociationSet Name="FK_Player_Team1" Association="TestModel.FK_Player_Team1">
9 <End Role="Team" EntitySet="Teams" />
10 <End Role="Player" EntitySet="Players" />
11 </AssociationSet>
12 <AssociationSet Name="FK_PlayerDetails_Player" Association="TestModel.FK_PlayerDetails_Player">
13 <End Role="Player" EntitySet="Players" />
14 <End Role="PlayerDetails" EntitySet="PlayerDetails" />
15 </AssociationSet>
16 </EntityContainer>
注意:Lazy Loading的設定是針對所有Model的,並非某一個Model。
下面,我們寫一段簡單的代碼來測試一下Lazy Loading:
View Code
using (var context = new TestEntities())
{
IQueryable<Team> teams = from t in context.Teams select t;
foreach (Team t in teams)
{
Console.WriteLine(t.Players.Count());
}
Console.Read();
}
運行後的結果如:
圖3
我們可以看到,在query語句中,我們只是要求返回所有的team資訊,並沒有像資料庫請求載入player的資訊,但在Foreach語句中,我們要求列印出每支team的player數量,卻成功了,這就是Lazy Loading實現的效果。實際上,當執行Count語句時,程式會再去取請求資料庫,返回player資訊,這也就是說,如果我們有100支球隊,程式會訪問100次資料庫來執行此操作。
下面我們關閉Lazy Loading來看看效果。關閉Lazy Loading有多種方法,我們可以在圖2的屬性視窗直接將Lazy Loading Enabled設定為False,也可以在XML代碼中將Lazy Loading Enabled賦值False,以下我們用程式碼來關閉Lazy Loading並執行上面代碼來看一下效果:
View Code
using (var context = new TestEntities())
{
//Disable Lazy Loading
context.ContextOptions.LazyLoadingEnabled = false;
IQueryable<Team> teams = from t in context.Teams select t;
foreach (Team t in teams)
{
Console.WriteLine(t.Players.Count());
}
Console.Read();
}
執行結果如下:
圖4
從執行結果我們可以看到,當執行Foreach語句時,程式並沒有去查詢資料庫,而我們的query語句又沒有向資料庫請求關於player的資訊,故無法列印出player的數量。
最後我們來總結一下Lazy Loading的優勢和劣勢:當開啟Lazy Loading時,我們可以不用去在意某實體是否已經載入,不會出現在調用某一實體時,出現null的尷尬,省去程式員不少心力,但同時劣勢也非常明顯,如果我們有大量實體,且頻繁去調用相關實體,程式就會頻繁地訪問資料庫,這很顯然地會影響程式的效能。