オブジェクト クエリ (Entity Framework)
ObjectQuery ジェネリック クラスは、0 個以上の型指定されたオブジェクトのコレクションを返せるクエリを表します。 ObjectQuery は、クエリの作成と実行に必要な接続情報とメタデータ情報を含む ObjectContext に属しています。 new 演算子を使用して ObjectQuery を構築し、クエリ文字列とオブジェクト コンテキストをコンストラクターに渡すことができます。 ただし、より一般的なシナリオでは、ObjectContext 派生クラスのプロパティを使用して、エンティティ セットのコレクションを表す ObjectQuery インスタンスを取得します。 通常、ObjectContext は Entity Framework ツールで生成されたクラスか POCO クラスによってサブクラス化され、オブジェクト コンテキストのプロパティは ObjectQuery (.NET Framework バージョン 3.5 SP1) として、または ObjectSet (.NET Framework バージョン 4) としてエンティティ セットを返します。 ObjectSet クラスは ObjectQuery クラスを拡張して、型指定されたエンティティ セットのコンテキストでオブジェクトの追加や削除などの機能を提供します。
既定の ObjectQuery は、指定された型のすべてのエンティティを返す開始クエリとなります。 このクエリは LINQ to Entities またはクエリ ビルダー メソッドを使用してさらに絞り込むことができます。
次の例では、Products
のコレクションのオブジェクト コンテキストのクエリを実行します。
Using context As New AdventureWorksEntities
Dim products As ObjectSet(Of Product) = context.Products
Dim productsQuery = _
From product In products _
Select product
Console.WriteLine("Product Names:")
For Each product In productsQuery
Console.WriteLine(product.Name)
Next
End Using
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
IQueryable<Product> productsQuery = from product in context.Products
select product;
Console.WriteLine("Product Names:");
foreach (var prod in productsQuery)
{
Console.WriteLine(prod.Name);
}
}
クエリの実行
オブジェクト クエリは次の状況で実行されます。
foreach (C#) または For Each (Visual Basic) ステートメントによって列挙された場合。
ToArray、ToDictionary、ToList などの集合演算によって列挙された場合。
Execute メソッドが明示的に呼び出された場合。
First や Any などの LINQ 演算子がクエリの最も外側で指定された場合。 詳細については、「クエリ ビルダー メソッド (Entity Framework)」を参照してください。
クエリを実行してもデータ ソースから何も返されない場合、結果には空のコレクションが含まれ、null は含まれていません。
Entity Framework によって実行されるクエリはデータ ソースのデータに対して評価されます。結果はオブジェクト コンテキストの新しいオブジェクトを反映するものにはなりません。 クエリの対象と同じ ID を持つエンティティが既にコンテキストにアタッチされている場合、データ ソースからのデータとコンテキストに既に存在するデータは、クエリの MergeOption に従ってマージされます。 キャッシュ内のデータを取得するには、ObjectStateManager クラスの GetObjectStateEntries メソッドを使用します。 ObjectStateManager はオブジェクト コンテキスト内のオブジェクトの状態を管理します。このため、追加されたオブジェクト、変更されたオブジェクト、および変更されなかったオブジェクトをすべて取得する場合、EntityState 値 (Added、Modified、Unchanged) のビット単位の OR を GetObjectStateEntries メソッドに渡すことができます。 詳細については、ローカル クエリの実行方法を解説したブログを参照してください。
次の例では、Execute メソッドを呼び出してクエリを実行します。
Using context As New AdventureWorksEntities()
Dim query As ObjectSet(Of Product) = context.Products
' Execute the query and get the ObjectResult.
Dim queryResult As ObjectResult(Of Product) = query.Execute(MergeOption.AppendOnly)
' Iterate through the collection of Product items.
For Each result As Product In queryResult
Console.WriteLine("{0}", result.Name)
Next
End Using
using (AdventureWorksEntities context =
new AdventureWorksEntities())
{
ObjectSet<Product> query = context.Products;
// Execute the query and get the ObjectResult.
ObjectResult<Product> queryResult = query.Execute(MergeOption.AppendOnly);
// Iterate through the collection of Product items.
foreach (Product result in queryResult)
Console.WriteLine("{0}", result.Name);
}
クエリ投影
オブジェクト クエリはよくエンティティ オブジェクトとして概念モデル データを返しますが、入れ子になった結果または匿名の投影に対してDbDataRecord オブジェクトを返したり、単一値のセットに対してプリミティブな CLR 型を返すこともできます。
LINQ to Entities と Entity SQL の両方でクエリ投影がサポートされます。 次の注意事項は、クエリの投影に適用されます。
一部の拡張メソッドは、入力として多数の結果のコレクションを必要とします。 ObjectQuery が単一のスカラー結果を含むコレクションを返すクエリを表す場合に、これらの拡張メソッドのいずれかを呼び出すと、次の例のように ArgumentException がスローされます。
' Define a query projection that returns ' a collection with a single scalar result. Dim scalarQuery As New ObjectQuery(Of Int32)("100", context) ' Calling an extension method that requires a collection ' will result in an exception. Dim hasValues As Boolean = scalarQuery.Any()
// Define a query projection that returns // a collection with a single scalar result. ObjectQuery<Int32> scalarQuery = new ObjectQuery<Int32>("100", context); // Calling an extension method that requires a collection // will result in an exception. bool hasValues = scalarQuery.Any();
プリミティブ型への投影時に ObjectQuery が null 値を返す可能性がある場合は、その型の NULL 許容バージョンを使用する必要があります。 次のクエリでは、SalesOrderHeader オブジェクトの ShipDate プロパティが null 値を返す可能性があるため、NULL 値を許容する DateTime を使用しています。
Dim shipDateQuery As ObjectQuery(Of Nullable(Of DateTime)) = _ context.SalesOrderHeaders.Where("it.CustomerID = @contactId", _ New ObjectParameter("contactId", contactId)).SelectValue(Of Nullable(Of DateTime))("it.ShipDate")
ObjectQuery<Nullable<DateTime>> shipDateQuery = context.SalesOrderHeaders .Where("it.CustomerID = @contactId", new ObjectParameter("contactId", contactId)) .SelectValue<Nullable<DateTime>>("it.ShipDate");
詳細については、「NULL 許容型 (Visual Basic プログラミング ガイド)」または「Nullable Types (C# Programming Guide)」を参照してください。
ストア コマンドの表示
概念モデルに対してクエリを実行すると、Entity Framework により、概念モデルに基づいた LINQ to Entities および Entity SQL クエリがデータ ソースに対する同等のクエリに変換されます。 Entity Framework には、System.Data.Objects.ObjectQuery.ToTraceString メソッドと System.Data.EntityClient.EntityCommand.ToTraceString メソッドが提供されており、これを使用すると、データ ソースに対するトレースを行わなくても、実行時にこれらのストア コマンドを表示できます。 詳細については、「格納コマンドを表示する方法 (Entity Framework)」を参照してください。
EntityKey によるオブジェクトの取得
エンティティのキー値がわかっている場合は、オブジェクト クエリを明示的に作成して実行しなくてもデータ ソースからキー値を取得できます。 ObjectContext の GetObjectByKey メソッドおよび TryGetObjectByKey メソッドは、指定された EntityKey と共に、オブジェクトをオブジェクト コンテキストに返します。 EntityKey が既存のエンティティに対応しない場合は、GetObjectByKey を使用するときに ObjectNotFoundException を処理する必要があります。 詳細については、「キーを使用して特定のオブジェクトを返す方法 (Entity Framework)」を参照してください。
参照
概念
概念モデルに対するクエリ (Entity Framework)
ObjectSet の使用 (Entity Framework)
コンパイル済みクエリ (LINQ to Entities)