データ サービスのクエリ (WCF Data Services)

WCF Data Services クライアント ライブラリを使用すると、言語統合クエリ (LINQ) を含め、使い慣れた .NET Framework プログラミング パターンを使用してデータ サービスに対してクエリを実行できます。このクライアント ライブラリは、クライアント上で DataServiceQuery クラスのインスタンスとして定義されたクエリを HTTP GET 要求メッセージに変換します。さらに応答メッセージを受け取り、クライアント データ サービス クラスのインスタンスに変換します。これらのクラスは、DataServiceQuery が属する DataServiceContext によって追跡されます。

データ サービス クエリ

DataServiceQuery ジェネリック クラスは、0 個以上のエンティティ型インスタンスのコレクションを返すクエリを表します。データ サービス クエリは、常に既存のデータ サービス コンテキストに属します。このコンテキストにより、クエリの作成と実行に必要なサービス URI とメタデータ情報が維持されます。

[サービス参照の追加] ダイアログを使用してデータ サービスを .NET Framework ベースのクライアント アプリケーションに追加すると、DataServiceContext クラスを継承するエンティティ コンテナー クラスが作成されます。このクラスには、型指定された DataServiceQuery インスタンスを返すプロパティが含まれます。データ サービスが公開するエンティティ セットごとに 1 つのプロパティがあります。これらのプロパティを使用すると、型指定された DataServiceQuery のインスタンスを簡単に作成できます。

クエリは次のシナリオで実行されます。

  • 次のように結果が暗黙的に列挙される場合

    • foreach (C#) ループや For Each (Visual Basic) ループなどで、エンティティ セットを表す DataServiceContext のプロパティが列挙されているとき

    • List コレクションにクエリが割り当てられているとき

  • Execute メソッドまたは BeginExecute メソッドが明示的に呼び出されたとき

  • FirstSingle などの LINQ クエリ実行演算子が呼び出されたとき

次のクエリを実行すると、Northwind データ サービスのすべての Customers エンティティが返されます。

' Define a new query for Customers.
Dim query As DataServiceQuery(Of Customer) = context.Customers
// Define a new query for Customers.
DataServiceQuery<Customer> query = context.Customers;

詳細については、「方法: データ サービス クエリを実行する (WCF Data Services)」を参照してください。

WCF Data Services クライアントでは遅延バインディング オブジェクトに対するクエリがサポートされていますが (C# で動的型を使用する場合など)、パフォーマンス上の理由から、データ サービスに対しては常に厳密に型指定されたクエリを作成するようにしてください。Tuple 型と動的オブジェクトはクライアントでサポートされていません。

LINQ クエリ

DataServiceQuery クラスは LINQ で定義された IQueryable インターフェイスを実装するので、WCF Data Services クライアント ライブラリは、エンティティ セット データに対する LINQ クエリを、データ サービス リソースに対して評価されるクエリ式を表す URI に変換できます。次の例は、前述の DataServiceQuery と同じ LINQ クエリです。ここでは、輸送費が 30 ドルを超える Orders を取得し、その結果を輸送費順に並べ替えます。

Dim selectedOrders = From o In context.Orders _
        Where (o.Freight > 30) _
        Order By o.ShippedDate Descending _
        Select o
var selectedOrders = from o in context.Orders
                     where o.Freight > 30
                     orderby o.ShippedDate descending 
                     select o;

この LINQ クエリは、Northwind ベースのクイック スタート データ サービスに対して実行される次のクエリ URI に変換されます。

https://localhost:12345/Northwind.svc/Orders?Orderby=ShippedDate&?filter=Freight gt 30
Dd673933.note(ja-jp,VS.100).gif注 :
LINQ 構文で表現できるクエリのセットは、データ サービスによって使用される REST (Representational State Transfer) ベースの URI 構文で有効なクエリのセットよりも範囲が広くなります。クエリを対象データ サービスの URI にマップできない場合、NotSupportedException が発生します。

詳細については、「LINQ に関する留意点 (WCF Data Services)」を参照してください。

クエリ オプションの追加

データ サービス クエリは、WCF Data Services で提供されるすべてのクエリ オプションをサポートしています。クエリ オプションを DataServiceQuery インスタンスに追加するには、AddQueryOption メソッドを呼び出します。AddQueryOption は、新しい DataServiceQuery インスタンスを返します。このインスタンスは元のクエリと同等ですが、新しいクエリ オプション セットを含みます。次のクエリを実行すると、Freight 値でフィルターされ、OrderID によって降順に並べ替えられた Orders が返されます。

' Define a query for orders with a Freight value greater than 30
' and that is ordered by the ship date, descending.
Dim selectedOrders As DataServiceQuery(Of Order) = context.Orders _
.AddQueryOption("$filter", "Freight gt 30") _
.AddQueryOption("$orderby", "OrderID desc")
// Define a query for orders with a Freight value greater than 30
// and that is ordered by the ship date, descending.
DataServiceQuery<Order> selectedOrders = context.Orders
    .AddQueryOption("$filter", "Freight gt 30")
    .AddQueryOption("$orderby", "OrderID desc");

$orderby クエリ オプションを使用すると、単一のプロパティに基づくクエリの並べ替えとフィルターの両方が可能です。次の例では、フィルターし、返された Orders オブジェクトを Freight プロパティの値に基づき並べ替えます。

' Create the DataServiceContext using the service URI.
Dim context = New NorthwindEntities(svcUri)

' Define a query for orders with a Freight value greater than 30
' that also orders the result by the Freight value, descending.
Dim selectedOrders As DataServiceQuery(Of Order) = _
context.Orders.AddQueryOption("$orderby", "Freight gt 30 desc")

Try
    ' Enumerate over the results of the query.
    For Each order As Order In selectedOrders
        Console.WriteLine("Order ID: {0} - Freight: {1}", _
                order.OrderID, order.Freight)
    Next
Catch ex As DataServiceQueryException
    Throw New ApplicationException( _
            "An error occurred during query execution.", ex)
End Try
// Create the DataServiceContext using the service URI.
NorthwindEntities context = new NorthwindEntities(svcUri);

// Define a query for orders with a Freight value greater than 30
// that also orders the result by the Freight value, descending.
DataServiceQuery<Order> selectedOrders = context.Orders
    .AddQueryOption("$orderby", "Freight gt 30 desc");

try
{
    // Enumerate over the results of the query.
    foreach (Order order in selectedOrders)
    {
        Console.WriteLine("Order ID: {0} - Freight: {1}",
            order.OrderID, order.Freight);
    }
}
catch (DataServiceQueryException ex)
{
    throw new ApplicationException(
        "An error occurred during query execution.", ex);
}

AddQueryOption メソッドを連続して呼び出すと、複雑なクエリ式を作成できます。詳細については、「方法: データ サービス クエリにクエリ オプションを追加する (WCF Data Services)」を参照してください。

クエリ オプションを使用して、LINQ クエリの構文要素を表すことができます。詳細については、「LINQ に関する留意点 (WCF Data Services)」を参照してください。

Dd673933.note(ja-jp,VS.100).gif注 :
AddQueryOption メソッドを使用してクエリ URI に $select クエリ オプションを追加することはできません。LINQ の Select メソッドを使用して、クライアントによって要求 URI に $select クエリ オプションが生成されるようにすることをお勧めします。

クライアントでの実行とサーバーでの実行

クライアントによるクエリの実行は 2 つの部分に分かれています。可能な限り、クエリ内の式は最初にクライアントで評価されます。その後、URI ベースのクエリが生成され、データ サービスに送信されて、サービス内のデータに対して評価されます。次の LINQ クエリについて考えてみましょう。

Dim basePrice As Integer = 100
Dim discount As Decimal = Convert.ToDecimal(0.1)

' Define a query that returns products based on a 
' calculation that is determined on the client.
Dim productsQuery = From p In context.Products
                  Where p.UnitPrice >
                  (basePrice - (basePrice * discount)) AndAlso
                  p.ProductName.Contains("bike")
                  Select p
int basePrice = 100;
decimal discount = .10M;

// Define a query that returns products based on a 
// calculation that is determined on the client.
var productsQuery = from p in context.Products
                  where p.UnitPrice >
                  (basePrice - (basePrice * discount)) &&
                  p.ProductName.Contains("bike")
                  select p;

この例では、式 (basePrice – (basePrice * discount)) はクライアントで評価されます。そのため、データ サービスに送信される実際のクエリ URI (https://localhost:12345/northwind.svc/Products()?$filter=(UnitPrice gt 90.00M) and substringof('bike',ProductName)) のフィルター句に計算済みの 10 進値 90 が含まれています。部分文字列式を含むフィルター式のその他の部分は、データ サービスによって評価されます。クライアントで評価される式は共通言語ランタイム (CLR) セマンティクスに従いますが、データ サービスに送信される式は OData プロトコルのデータ サービスの実装に依存します。また、このように別々に評価されることで予期しない結果が生じる場合があることにも注意する必要があります。たとえば、クライアントとサービスの両方で、異なるタイム ゾーンを使用して時間に基づく評価が実行される場合があります。

クエリ応答

DataServiceQuery を実行すると、要求したエンティティ型の IEnumerable が返されます。このクエリ結果は、次の例のように QueryOperationResponse オブジェクトにキャストできます。

' Execute the query for all customers and get the response object.
Dim response As QueryOperationResponse(Of Customer) = _
    CType(query.Execute(), QueryOperationResponse(Of Customer))
// Execute the query for all customers and get the response object.
QueryOperationResponse<Customer> response = 
    query.Execute() as QueryOperationResponse<Customer>;

データ サービスのエンティティを表すエンティティ型インスタンスは、オブジェクトの具体化というプロセスによってクライアントで作成されます。詳細については、「オブジェクトの具体化 (WCF Data Services)」を参照してください。QueryOperationResponse オブジェクトは、IEnumerable を実装してクエリ結果へのアクセスを提供します。

さらに、QueryOperationResponse には、クエリ結果に関する追加情報へのアクセスを可能にする次のメンバーが含まれます。

  • Error - 発生すると、操作によってエラーがスローされます。

  • Headers - クエリ応答に関連する HTTP 応答ヘッダーのコレクションが含まれます。

  • Query - QueryOperationResponse を生成した元の DataServiceQuery を取得します。

  • StatusCode - クエリ応答の HTTP 応答コードを取得します。

  • TotalCount - DataServiceQueryIncludeTotalCount メソッドが呼び出されるとエンティティ セット内のエンティティの合計数を取得します。

  • GetContinuation - 結果の次のページの URI を含む DataServiceQueryContinuation オブジェクトを返します。

既定では、WCF Data Services はクエリ URI によって明示的に選択されたデータのみを返します。これにより、必要に応じてデータ サービスから追加のデータを明示的に読み込むことができます。データ サービスからデータを明示的に読み込むたびに要求がデータ サービスに送られます。明示的に読み込むことができるデータには、関連エンティティ、ページングされた応答データ、バイナリ データ ストリームがあります。

Dd673933.note(ja-jp,VS.100).gif注 :
データ サービスはページングされた応答を返す場合があるので、アプリケーションではページングされたデータ サービス応答を処理するプログラミング パターンを使用することをお勧めします。詳細については、「遅延コンテンツの読み込み (WCF Data Services)」を参照してください。

エンティティの特定のプロパティのみが応答で返されるように指定することにより、クエリによって返されるデータの量を削減することもできます。詳細については、「クエリ射影 (WCF Data Services)」を参照してください。

セット内のエンティティの合計数の取得

一部のシナリオでは、クエリによって返される数だけではなく、エンティティ セット内のエンティティの合計数を知っておくと役立ちます。このセット内のエンティティの合計数がクエリ結果に含まれるように要求するには、DataServiceQueryIncludeTotalCount メソッドを呼び出します。この場合、返された QueryOperationResponseTotalCount プロパティが、セット内のエンティティの合計数を返します。

さらに、Count メソッドまたは LongCount メソッドを呼び出すことにより、それぞれ Int32 値または Int64 値として、セット内のエンティティの合計数のみを取得することもできます。これらのメソッドを呼び出すと、QueryOperationResponse は返されず、カウント値のみが返されます。詳細については、「方法: クエリで返されたエンティティの数を確認する (WCF Data Services)」を参照してください。

このセクションの内容

クエリ射影 (WCF Data Services)

オブジェクトの具体化 (WCF Data Services)

LINQ に関する留意点 (WCF Data Services)

方法: データ サービス クエリを実行する (WCF Data Services)

方法: データ サービス クエリにクエリ オプションを追加する (WCF Data Services)

方法: クエリで返されたエンティティの数を確認する (WCF Data Services)

方法: データ サービス要求のクライアント資格情報を指定する (WCF Data Services)

方法: クライアント要求のヘッダーを設定する (WCF Data Services)

方法: クエリ結果を射影する (WCF Data Services)

参照

その他のリソース

WCF Data Services クライアント ライブラリ