Entity Framework加載相關實體——Lazy Loading


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的尷尬,省去程序員不少心力,但同時劣勢也非常明顯,如果我們有大量實體,且頻繁去調用相關實體,程序就會頻繁地訪問數據庫,這很顯然地會影響程序的性能。

下一次我們會來分析關閉Lazy Loading的情況下,如何顯示加載相關實體,即Explicit Loading。







免責聲明!

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



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