為查詢結果定形 (Entity Framework)
執行查詢時只會傳回在查詢中明確要求的物件。 舉例來講,當針對 Adventure Works Sales Model 的查詢傳回 Customer 物件時,根據預設並不會傳回相關的 SalesOrderHeader 物件,但是在 Customer 和 SalesOrderHeader 之間卻會有關聯性。 這種行為可確保應用程式永遠知道從物件查詢所傳回資料的範圍。 根據預設,表示實體類型之間關聯的關聯性物件一定會傳回。 依據 EDM 的概念結構描述產生物件時,也會在關聯的兩端產生實體物件的導覽屬性。 這些導覽屬性會在一對一或多對一聯聯性的「一」端傳回 EntityReference,或在一對多或多對多關聯性的「多」端傳回 EntityCollection。 如需詳細資訊,請參閱 Entity Data Model 關聯性。
您可以使用導覽屬性撰寫明確導覽這些關聯性的 實體 SQL 或 LINQ 到實體 查詢。 如需詳細資訊,請參閱 HOW TO:使用導覽屬性巡覽關聯性 (Entity Framework)。 不過您不需要在查詢中明確導覽關聯性來為查詢結果定形。 有兩種方式可將查詢結果擴充為也載入參考的物件:您可以指定查詢路徑,也可以使用導覽屬性明確載入相關物件。 如果要進一步控制結果,您可以定義查詢路徑,然後只明確載入選取的相關物件。
在考慮要使用哪一種方式時,請特別留意,在對資料庫進行的要求數目與單一查詢所傳回的資料量之間必須有所取捨。 查詢路徑將定義查詢所傳回物件的圖形。 定義查詢路徑時,只需對資料庫進行單一要求即可在單一結果集中傳回此路徑定義的所有物件。 明確載入物件必須多次往返資料庫而且可能需要 Multiple Active Result Set (MARS),但是傳回的資料量僅限於所載入的物件。
定義查詢路徑來為查詢結果定形
如果要指定查詢路徑,請將代表物件圖形的字串傳遞給 ObjectQuery 上的 Include 方法。 這個路徑會指定在執行物件查詢時要傳回哪些相關物件。 例如,在 Contact 物件的查詢上定義的查詢路徑將會傳回每一個相關的 SalesOrderHeader 和 SalesOrderDetail。 下列查詢會示範使用 LINQ 到實體、實體 SQL 和查詢產生器方法。
- LINQ 到實體
``` vb
' Define a LINQ query with a path that returns
' orders and items for a contact.
Dim contacts = (From contact In context.Contact _
.Include("SalesOrderHeader.SalesOrderDetail") _
Select contact).FirstOrDefault()
```
``` csharp
// Define a LINQ query with a path that returns
// orders and items for a contact.
var contacts = (from contact in context.Contact
.Include("SalesOrderHeader.SalesOrderDetail")
select contact).FirstOrDefault();
```
- 實體 SQL
``` vb
' Define an object query with a path that returns
' orders and items for a specific contact.
Dim queryString As String = _
"SELECT VALUE TOP(1) Contact FROM " + _
"AdventureWorksEntities.Contact AS Contact"
' Define the object query with the query string.
Dim contactQuery As New ObjectQuery(Of Contact)(queryString, _
context, MergeOption.NoTracking)
Dim contact As Contact = _
contactQuery.Include("SalesOrderHeader.SalesOrderDetail") _
.FirstOrDefault()
```
``` csharp
// Define an object query with a path that returns
// orders and items for a specific contact.
string queryString =
@"SELECT VALUE TOP(1) Contact FROM " +
"AdventureWorksEntities.Contact AS Contact";
// Define the object query with the query string.
ObjectQuery<Contact> contactQuery = new ObjectQuery<Contact>(queryString,
context, MergeOption.NoTracking);
Contact contact =
contactQuery.Include("SalesOrderHeader.SalesOrderDetail")
.FirstOrDefault();
```
查詢產生器方法
' Create an object query with a path that returns orders and items for a contact. Dim contact As Contact = _ context.Contact.Include("SalesOrderHeader.SalesOrderDetail") _ .FirstOrDefault()
// Define an object query with a path that returns // orders and items for a specific contact. Contact contact = context.Contact.Include("SalesOrderHeader.SalesOrderDetail") .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.SalesOrderHeader.Include("SalesOrderDetail").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.SalesOrderHeader.Include("SalesOrderDetail").Include("Address");
使用查詢路徑可能會使表面上簡單的物件查詢變成要針對資料來源執行複雜的命令。 發生這種情況是因為必須進行一或多次聯結才能在單一查詢中傳回相關物件。 在針對複雜 EDM (例如具有繼承的實體或包含多對多關聯性的路徑) 的查詢中,這種複雜性會變得更大。 使用 ToTraceString 方法可查看將會由 ObjectQuery 產生的命令。 如需詳細資訊,請參閱物件查詢 (Entity Framework)。 如果查詢路徑包含太多相關物件,或是物件包含太多資料列資料,資料來源可能會無法完成查詢。 如果查詢需要超過資料來源能力的中繼暫時儲存體,就會發生這種情況。 發生這種情況時,請明確載入相關物件來降低資料來源查詢的複雜性。
如需詳細資訊,請參閱 HOW TO:使用查詢路徑來設定結果外觀 (Entity Framework)。
明確載入相關物件
如果要明確載入相關物件,請在導覽屬性所傳回的相關端點上呼叫 Load 方法。 如果是一對多關聯性,請在 EntityCollection 上呼叫 Load 方法,如果是一對一關聯性,請在 EntityReference 上呼叫 Load。 這樣就會將相關物件資料載入物件內容中。 當查詢傳回物件的集合時,您可以逐一列舉此集合並且呼叫 Load 方法針對集合中的每個物件載入相關物件,例如屬於 SalesOrderHeader 物件的每一個 SalesOrderDetail 物件。 以下範例會針對所指定 SalesOrderHeader 物件明確載入SalesOrderDetail 物件。
' Load the items for the order if not already loaded.
If Not order.SalesOrderDetail.IsLoaded Then
order.SalesOrderDetail.Load()
End If
// Load the items for the order if not already loaded.
if (!order.SalesOrderDetail.IsLoaded)
{
order.SalesOrderDetail.Load();
}
附註 |
---|
於 foreach (C#) 或 For Each (Visual Basic) 列舉期間呼叫 Load 方法時,物件服務會嘗試開啟新的資料讀取器。 除非您在連接字串中指定 multipleactiveresultsets=true 啟用多個現用結果集,否則這項作業將會失敗。 如需詳細資訊,請參閱 MSDN 上的使用多重現用結果集 (MARS)。 您也可以將查詢結果載入 List 集合,它們關閉資料取器並可讓您列舉此集合來載入參考的物件。 |
如需詳細資訊,請參閱 HOW TO:明確載入相關的物件 (Entity Framework)。
查詢相關物件
由於 EntityCollection 類別會實入 IEnumerable 介面,所以您可以使用 LINQ 查詢由導覽屬性所傳回載入 EntityCollection 中的物件集合。 不論是指定查詢路徑以隱含方式將物件載入物件內容,或呼叫 Load 方法明確載入物件,都可採用這種方式。
在 EntityCollection 上呼叫 CreateSourceQuery 方法可以讓您查詢相關物件,而不用先將物件載入集合。CreateSourceQuery 會傳回 ObjectQuery,經執行後,便會傳回與呼叫 Load 方法相同的物件集。 查詢產生器方法可套用在此物件查詢,藉此進一步篩選載入集合中的物件。 如需詳細資訊,請參閱 HOW TO:在 EntityCollection 中查詢相關物件 (Entity Framework)。
ObjectQuery 會將 EDM 資料傳回成為實體物件。 不過在查詢投影中包括導覽屬性時,ObjectQuery 會傳回包含相關物件的巢狀 DbDataRecord。 如需詳細資訊,請參閱 HOW TO:使用導覽屬性巡覽關聯性 (Entity Framework)。
另請參閱
概念
以物件形式查詢資料 (Entity Framework)
物件查詢 (Entity Framework)
查詢產生器方法 (Entity Framework)