LINQ to Entities 執行流程
針對 Entity Framework 執行的查詢是以命令樹查詢來表示,每一個查詢都會針對物件內容來執行。LINQ to Entities 會將 Language-Integrated Queries (LINQ) 查詢轉換成命令樹查詢、針對 Entity Framework 執行查詢,並傳回 Entity Framework 和 LINQ 都可以使用的物件。下列是建立及執行 LINQ to Entities 查詢的程序:
從 ObjectContext 建構 ObjectQuery 執行個體。
使用 ObjectQuery 執行個體,在 C# 或 Visual Basic 中撰寫 LINQ to Entities 查詢。
將 LINQ 標準查詢運算子和運算式轉換成命令樹。
在命令樹中會針對資料來源查詢執行。執行期間於資料來源上擲回的任何例外狀況都會直接傳遞給用戶端。
將查詢結果傳回用戶端。
建構 ObjectQuery 執行個體
ObjectQuery 泛型類別表示傳回零個或多個具型別實體之集合的查詢。物件查詢通常是從現有的物件內容所建構 (而不是手動建構),而且一定會屬於該物件內容。此內容提供了撰寫及執行查詢所需的連接和中繼資料資訊。ObjectQuery 泛型類別會實作 IQueryable 泛型介面,此介面的 builder 方法可累加建置 LINQ 查詢。
撰寫查詢
實作泛型 IQueryable 介面之 ObjectQuery 泛型類別的執行個體會當做 LINQ to Entities 查詢的資料來源。在查詢中,您可以精確地指定想要從資料來源中擷取的資訊。此外,查詢也可以指定該項資訊傳回之前應該如何排序、分組和成形。在 LINQ 中,查詢會儲存在變數內。這個查詢變數不會採取任何動作,也不會傳回任何資料。它只會儲存查詢資訊。在您建立查詢之後,必須執行該查詢以便擷取任何資料。
LINQ to Entities 查詢可以使用兩個不同的語法來撰寫:查詢運算式語法和以方法為基礎的查詢語法。查詢運算式語法和以方法為基礎的查詢語法都是 C# 3.0 和 Visual Basic 9.0 中的新增功能。
如需詳細資訊,請參閱 LINQ to Entities 中的查詢。
下列查詢運算式語法的範例會從 AdventureWorks 物件內容建構 ObjectQuery 執行個體,並使用 Select 傳回 Product 中的所有資料列。
Using AWEntities As New AdventureWorksEntities
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productNames = _
From p In products _
Select p
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<Product> productNames =
from p in products
select p;
}
下列以方法為基礎的查詢語法範例會從 AdventureWorks 物件內容建構 ObjectQuery 執行個體,並使用 Select 傳回 Product 中的所有資料列。
Using AWEntities As New AdventureWorksEntities
Dim productNames = AWEntities.Product.Select(Function(p) p.Name)
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<Product> productNames = products.Select(p => p);
}
查詢轉換
若要針對 Entity Framework 執行 LINQ to Entities 查詢,LINQ 查詢必須轉換成可以針對 Entity Framework 執行的命令樹表示法。
LINQ to Entities 查詢是由 LINQ 標準查詢運算子 (如 Select、Where 和 GroupBy) 和運算式 (x > 10、Contact.LastName 等等) 所組成。LINQ 運算子並不是由類別所定義,而是類別上的方法。在 LINQ 中,運算式可以包含 System.Linq.Expressions 命名空間內類型所允許的任何項目,以及能以 Lambda 函式表示的任何項目 (依擴充而定)。這是 Entity Framework 所允許之運算式的超集,根據定義,這些運算式限制為只有資料庫上允許且 ObjectQuery 支援的作業。
在 Entity Framework 中,運算子和運算式都是由單一型別階層所代表,然後會將它們置於命令樹中。Entity Framework 會使用此命令樹來執行查詢。如果 LINQ 查詢不能表示為命令樹,則當轉換查詢時,將會擲回例外狀況。LINQ to Entities 查詢的轉換牽涉到兩個子轉換:標準查詢運算子的轉換及運算式的轉換。
許多 LINQ 標準查詢運算子沒有 LINQ to Entities 中的有效轉譯。嘗試使用這些運算子將會在查詢轉譯時產生例外狀況。如需支援的 LINQ to Entities 運算子清單,請參閱支援與不支援的方法 (LINQ to Entities)。
如需在 LINQ to Entities 中使用標準查詢運算子的詳細資訊,請參閱 LINQ to Entities 查詢中的標準查詢運算子。
一般來說,LINQ to Entities 中的運算式會在伺服器上評估,所以運算式的行為不需要遵循 CLR 語意。如需詳細資訊,請參閱 LINQ to Entities 查詢中的運算式。
查詢執行
當使用者建立 LINQ 查詢之後,會將它轉換成與 Entity Framework 相容的表示法 (命令樹的形式),然後針對資料來源執行此查詢。在執行查詢時,所有的查詢運算式 (或是查詢的元件) 都會在用戶端或伺服器上評估,這包括用於結果具體化或實體投影的運算式。
執行查詢運算式的時間可能會有所不同。每當反覆查看查詢變數 (而非建立查詢變數) 時,就會執行 LINQ 查詢;這稱為延後執行。也可以強制立即執行此查詢,這對於快取查詢結果很有用處。下列範例會使用 Select 來傳回 Product 中的所有資料列,並顯示產品名稱。反覆查看 foreach/For Each 迴圈中的查詢變數會造成此查詢的執行。
Using AWEntities As New AdventureWorksEntities
Dim products As ObjectQuery(Of Product) = AWEntities.Product
Dim productNames = _
From p In products _
Select p.Name
Console.WriteLine("Product Names:")
For Each productName In productNames
Console.WriteLine(productName)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
ObjectQuery<Product> products = AWEntities.Product;
IQueryable<string> productNames =
from p in products
select p.Name;
Console.WriteLine("Product Names:");
foreach (var productName in productNames)
{
Console.WriteLine(productName);
}
}
執行 LINQ to Entities 查詢時,查詢中的某些運算式可能會在伺服器上執行,而某些部分則可能在本機用戶端上執行。在伺服器上執行查詢以前,會先在用戶端評估運算式。如果運算式是在用戶端上評估,該評估的結果會代替查詢中的運算式,然後會在伺服器上執行查詢。由於查詢會在資料存來源執行,所以資料來源組態會覆寫用戶端中指定的行為。Null 值處理和數字整數位數都是此情況的案例。在伺服器上執行查詢的期間擲回的任何例外狀況,都會直接傳遞給用戶端。如需詳細資訊,請參閱查詢執行。
具體化
具體化是將查詢結果以 CLR 型別形式傳回用戶端的程序。在 LINQ to Entities 中,絕對不會傳回查詢結果資料記錄;一定會有支援的 CLR 型別,該型別是由使用者或 Entity Framework 所定義或是由編譯器所產生 (匿名型別)。所有物件具體化都是由 Entity Framework 執行。因為無法在 Entity Framework 與 CLR 之間對應而產生的任何錯誤,都將導致物件具體化期間擲回例外狀況。
查詢結果通常會以下列其中一個項目的形式來傳回:
零個或多個具型別實體物件的集合或是 EDM 中複雜類型的投影。
EDM 所支援的 CLR 型別。
內嵌集合。
匿名型別。
如需詳細資訊,請參閱查詢結果。