LINQ to Entities の実行フロー
Entity Framework に対するクエリで代表的なものが、コマンド ツリー クエリです。これはオブジェクト コンテキストに対して実行されます。LINQ to Entities では、統合言語クエリ (LINQ) クエリをコマンド ツリー クエリに変換し、そのクエリを Entity Framework に対して実行します。返されたオブジェクトは、Entity Framework でも LINQ でも使用できます。次に、LINQ to Entities クエリを作成して実行する手順を示します。
ObjectContext から ObjectQuery インスタンスを作成します。
ObjectQuery インスタンスを使用して、C# または Visual Basic で LINQ to Entities クエリを作成します。
LINQ 標準クエリ演算子および標準クエリ式をコマンド ツリーに変換します。
コマンド ツリーで表されたクエリをデータ ソースに対して実行します。実行中にデータ ソースに対してスローされた例外は、クライアントに直接渡されます。
クエリの結果をクライアントに返します。
ObjectQuery インスタンスの構築
ObjectQuery ジェネリック クラスは、0 個以上の型指定されたエンティティのコレクションを返すクエリを表します。通常、オブジェクト クエリは手作業で構築されるのではなく、既存のオブジェクト コンテキストから構築され、常にそのオブジェクト コンテキストに属しています。このコンテキストにより、クエリの作成と実行に必要な接続情報とメタデータ情報が取得されます。ObjectQuery ジェネリック クラスでは、IQueryable ジェネリック インターフェイスが実装されます。このインターフェイスのビルダ メソッドにより、LINQ クエリを段階的に構築できます。
クエリの作成
IQueryable ジェネリック インターフェイスを実装する ObjectQuery ジェネリック クラスのインスタンスは、LINQ to Entities クエリのデータ ソースとして動作します。クエリでは、データ ソースから取得する情報を正確に指定できます。また、並べ替え、グループ化、整形方法を指定して情報を取得することもできます。LINQ では、クエリが変数に格納されます。このクエリ変数は、クエリの情報を保存するだけで、なんらかのアクションを実行したり、データを返したりすることはありません。クエリを作成した後、データを取得するには、そのクエリを実行する必要があります。
LINQ to Entities クエリは、クエリ式の構文とメソッド ベースのクエリ構文という 2 とおりの構文を使って作成できます。クエリ式の構文とメソッド ベースのクエリ構文は、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);
}
クエリの変換
LINQ to Entities クエリを Entity Framework に対して実行するには、LINQ クエリを Entity Framework に対して実行できるコマンド ツリー表現に変換する必要があります。
LINQ to Entities クエリは、LINQ 標準クエリ演算子 (Select、Where、GroupBy など) と式 (x > 10 や Contact.LastName など) で構成されます。LINQ 演算子はクラスで定義されるものではなく、クラスのメソッドです。LINQ の式には、System.Linq.Expressions 名前空間の型で許容される要素だけでなく、ラムダ関数で表される要素であれば何でも使用できます。これは Entity Framework で許容される式のスーパーセットです。定義により、このような式はデータベースで許容され、ObjectQuery でサポートされる操作に限定されています。
Entity Framework では、演算子と式は 1 つの型の階層で表された後、コマンド ツリーに配置されます。このコマンド ツリーが、Entity Framework でのクエリの実行に使用されます。LINQ クエリをコマンド ツリーとして表現できない場合、クエリの変換中に例外がスローされます。LINQ to Entities クエリを変換する際には、標準クエリ演算子の変換と式の変換という 2 つの変換が実行されます。
LINQ to Entities で正しく変換されない LINQ 標準クエリ演算子は多数あります。このような演算子を使用すると、クエリの変換時に例外が発生します。サポートされる 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 では、クエリの結果のデータ レコードは決して返されません。常に返されるのは、ユーザーまたは Entity Framework で定義された CLR 型、またはコンパイラによって生成される CLR 型 (匿名型) です。オブジェクトの具体化は、すべて Entity Framework によって実行されます。Entity Framework と CLR とのマッピングができないことが原因でエラーが発生すると、オブジェクトの具体化中に例外がスローされます。
通常、クエリの結果は次のいずれかの形で返されます。
0 個以上のエンティティ オブジェクトのコレクション、または EDM の複合型の投影。
EDM でサポートされる CLR 型。
インライン コレクション。
匿名型。
詳細については、「クエリ結果」を参照してください。