載入相關的物件 (Entity Framework)

本主題描述可用於載入相關實體的模式。 實體類型可以定義在資料模型中代表關聯的導覽屬性。 您可以使用這些屬性,依照已定義的關聯載入與傳回之實體有關的實體。 根據資料模型產生實體時,也會在關聯的兩端產生實體的導覽屬性。 這些導覽屬性會在一對一或多對一關聯性的「一」端傳回參考,或在一對多或多對多關聯性的「多」端傳回集合。 如需詳細資訊,請參閱導覽屬性定義及管理關聯性

下列模式描述可用於載入相關實體的方式:

載入模式 說明

在查詢中指定

您可以使用導覽屬性來撰寫明確巡覽關聯性的 Entity SQL 或 LINQ to Entities 查詢。 當您執行此類查詢時,系統會傳回查詢最外層投影中的相關實體 (這些實體以導覽屬性的形式包含在其中)。 如需詳細資訊,請參閱

HOW TO:使用導覽屬性巡覽關聯性 (Entity Framework).

明確式載入

將實體明確載入 ObjectContext 必須多次反覆存取資料庫,而且可能需要 Multiple Active Result Set (MARS),但是傳回的資料量僅限於所載入的實體。 若要從資料來源明確擷取相關實體,請針對 EntityCollectionEntityReference 使用 Load 方法,或是針對 ObjectContext 使用 LoadProperty 方法。 每次呼叫 Load 方法都會開啟資料庫的連接,以擷取相關資訊。 這樣可以確保在未明確要求相關實體的情況下,絕對不會執行查詢。 明確式載入是 Entity Framework 的預設行為。

Bb896272.note(zh-tw,VS.100).gif注意:
呼叫 Load 之前,系統已將與相關實體有關的少量資訊載入 ObjectContext

如需詳細資訊,請參閱本主題的<Explicitly Loading Related Objects>一節。

消極式載入

此載入類型會在您存取導覽屬性時,從資料來源自動載入相關實體。 使用此載入類型時請注意,如果實體原本不存在 ObjectContext 中,您所存取的每個導覽屬性都會產生一個針對資料來源執行的獨立查詢。

如需詳細資訊,請參閱本主題的<Lazy Loading>一節。

積極式載入

使用 Include 定義查詢路徑

當您知道應用程式所需之相關實體的確切圖形圖案時,就可以針對 ObjectQuery 使用 Include 方法來定義查詢路徑,以便控制要在初始查詢中傳回哪些相關實體。 當您定義查詢路徑時,只要針對資料庫提出單一要求,即可在單一結果集中傳回此路徑所定義的所有實體,而且系統會使用查詢所傳回的每個物件來載入路徑中指定之類型的所有相關實體。

如需詳細資訊,請參閱本主題的<Defining a Query Path to Shape Query Results>一節。

明確載入相關的實體物件

若要明確載入相關實體,您必須在導覽屬性所傳回的相關端點上呼叫 Load 方法。 如果是一對多關聯性,請在 EntityCollection 上呼叫 Load 方法,如果是一對一關聯性,請在 EntityReference 上呼叫 Load 方法。 如果您要使用 POCO 實體,請針對 ObjectContext 使用 LoadProperty 方法。 如需詳細資訊,請參閱載入相關的 POCO 實體 (Entity Framework)。 此外,LoadProperty 方法也可以搭配衍生自 EntityObject 的實體使用。 這些方法會將相關物件資料載入物件內容中。 當查詢傳回結果時,您可以使用 foreach 迴圈 (Visual Basic 中的 For Each...Next) 來逐一列舉物件的集合,並且針對結果中每個實體的 EntityReferenceEntityCollection 屬性,有條件地呼叫 Load 方法。

Bb896272.note(zh-tw,VS.100).gif注意:
foreach (C#) 或 For Each (Visual Basic) 列舉期間呼叫 Load 方法時,Entity Framework 會嘗試開啟新的資料讀取器。除非您在連接字串中指定 multipleactiveresultsets=true 啟用多個現用結果集,否則這項作業將會失敗。如需詳細資訊,請參閱 MSDN 上的使用多重現用結果集 (MARS)。您也可以將查詢結果載入 List 集合中,以便關閉資料讀取器並且讓您列舉此集合來載入參考的實體。

如需詳細資訊,請參閱 HOW TO:明確載入相關的物件 (Entity Framework)

定義查詢路徑來為查詢結果定形

若要指定查詢路徑,請將代表物件圖形的字串傳遞給 ObjectQuery 上的 Include 方法。 這個路徑會指定在執行物件查詢時要傳回哪些相關實體。 例如,在 Contact 物件的查詢上定義的查詢路徑可確保將會傳回每個相關的 SalesOrderHeaderSalesOrderDetail。 下列查詢將顯示此做法:

' Define a LINQ query with a path that returns 
' orders and items for a contact. 
Dim contacts = (From contact In context.Contacts.Include("SalesOrderHeaders.SalesOrderDetails") _
    Select contact).FirstOrDefault()
// Define a LINQ query with a path that returns 
// orders and items for a contact.
var contacts = (from contact in context.Contacts
              .Include("SalesOrderHeaders.SalesOrderDetails")
                select contact).FirstOrDefault();

定義查詢路徑時請列入下列考量因素:

  • 查詢路徑可以搭配查詢產生器方法和 LINQ 查詢使用。

  • 當您呼叫 Include 時,此查詢路徑只適用於 ObjectQuery 的傳回執行個體。 其他 ObjectQuery 執行個體和物件內容本身則不會受到影響。

  • 由於 Include 會傳回查詢物件,因此您可以在 ObjectQuery 上多次呼叫這個方法,從多個關聯性納入實體,如下列範例所示:

    ' Create a SalesOrderHeader query with two query paths, 
    ' one that returns order items and a second that returns the 
    ' billing and shipping addresses for each order. 
    Dim query As ObjectQuery(Of SalesOrderHeader) = context.SalesOrderHeaders.Include("SalesOrderDetails").Include("Address")
    
    // Create a SalesOrderHeader query with two query paths, 
    // one that returns order items and a second that returns the 
    // billing and shipping addresses for each order.
    ObjectQuery<SalesOrderHeader> query =
        context.SalesOrderHeaders.Include("SalesOrderDetails").Include("Address");
    
  • 使用查詢路徑可能會使表面上簡單的物件查詢變成要針對資料來源執行複雜的命令。 發生這種情況,是因為需要一個以上的聯結才能在單一查詢中傳回相關物件,如此會導致從資料來源傳回每個相關實體的多餘資料。 在針對複雜模型 (例如具有繼承的實體或包含多對多關聯性的路徑) 的查詢中,這種複雜性會變得更大。 使用 ToTraceString 方法可查看將會由 ObjectQuery 產生的命令。 如果查詢路徑包含太多相關物件,或是物件包含太多資料列資料,資料來源可能會無法完成查詢。 如果查詢需要超過資料來源能力的中繼暫時儲存體,就會發生這種情況。 發生這種情況時,請明確載入相關物件或啟用延後載入,降低資料來源查詢的複雜性。 如果最佳化複雜查詢之後,您仍然經常遇到逾時的情況,請考慮設定 CommandTimeout 屬性來增加逾時值。

如需詳細資訊,請參閱 HOW TO:使用查詢路徑來設定結果外觀 (Entity Framework)

消極載入實體物件

Entity Framework 支援相關實體的消極式載入。 在 Entity Framework 執行階段中,ObjectContext 執行個體之 LazyLoadingEnabled 屬性的預設值是 false。 不過,如果您使用 Entity Framework 工具來建立新的模型和對應的產生類別,在物件內容的建構函式中,LazyLoadingEnabled 會設定為 true。 若啟用消極式載入,在導覽屬性的 get 存取子以程式設計的方式存取相關實體之前,不會從資料來源載入相關實體。 若要停用消極式載入,請在 System.Data.Objects.ObjectContext.ContextOptions 屬性傳回的 ObjectContextOptions 執行個體上,將 LazyLoadingEnabled 屬性設定為 false

消極式載入可與積極式載入一起使用。 透過這種方式,您可以使用查詢路徑來定義基底資料圖形,也可以視需要載入不包括在原始查詢路徑中的其他相關實體。 如需詳細資訊,請參閱 HOW TO:使用消極式載入來載入相關物件 (Entity Framework)

使用消極式載入時,應考量下列項目:

  • 消極式載入支援可同時傳回單一實體 (例如 EntityReference) 和實體集合 (例如 EntityCollection) 的導覽屬性。

  • 如果已啟用消極式載入而且已載入相關實體,則不會再次載入。

  • 消極式載入支援處於 Detached 狀態的實體。 在這種情況中,也會傳回處於 Detached 狀態的相關物件。

  • 消極式載入行為是由 ObjectContext 執行個體判斷,該執行個體是用來從資料來源擷取物件 (即使實體是使用 NoTracking MergeOption 載入),或是加入或附加物件的執行個體。 因此,一旦公開此內容,就不能變更消極式載入行為,任何進一步的消極式載入作業都會失敗。

  • 序列化實體時,請考慮停用消極式載入。 否則,系統會觸發消極式載入,而且序列化的實體可能會加入比預期還多的資料。

使用消極式載入搭配 POCO 實體時,則適用其他考量因素。 如需詳細資訊,請參閱載入相關的 POCO 實體 (Entity Framework)

查詢相關的實體物件

EntityCollection 上呼叫 CreateSourceQuery 方法可讓您查詢相關物件,而不必先載入物件至集合。 CreateSourceQuery 會傳回 ObjectQuery,執行這查詢時,會與呼叫 Load 方法一樣,傳回相同的物件集。 查詢產生器方法可套用至此物件查詢,藉此進一步篩選載入集合中的物件。 如需詳細資訊,請參閱 HOW TO:在 EntityCollection 中查詢相關物件 (Entity Framework)

ObjectQuery 會將實體資料當做實體傳回。 不過,在最外層查詢投影中包括導覽屬性時,查詢也會傳回經由巡覽存取的相關實體。 如需詳細資訊,請參閱 HOW TO:使用導覽屬性巡覽關聯性 (Entity Framework)

效能考量

當您選擇載入相關實體的模式時,請針對資料來源連接次數及時間考慮每個方法的行為,以及使用單一查詢傳回的資料量及複雜度。 積極式載入會在單一查詢中傳回所有相關實體以及所查詢的實體。 也就是說,雖然只連接資料來源一次,但會在初始查詢中傳回大量的資料。 同時,查詢路徑會產生較複雜的查詢,因為針對資料來源執行的查詢需要額外的聯結。

明確載入和消極式載入都可以讓您延遲相關物件資料的要求,直到確實需要該資料為止。 這樣可以產生複雜性較低的初始查詢,所傳回的總資料量也較少。 不過,後續每次載入相關物件時,都會連接資料來源並執行查詢。 若使用消極式載入,每當存取導覽屬性且尚未載入相關實體時,就會發生此連接。 如果您擔心初始查詢傳回的相關實體,或是管理相關實體從資料來源載入的時機,就應該考慮停用消極式載入。 在 Entity Framework 產生之物件內容的建構函式中已啟用消極式載入。

如需詳細資訊,請參閱 效能考量因素 (Entity Framework)

另請參閱

概念

查詢概念模型 (Entity Framework)
物件查詢 (Entity Framework)
查詢產生器方法 (Entity Framework)