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

このトピックでは、WCF Data Services クライアントを使用しているときに LINQ クエリを作成および実行する方法と、Open Data Protocol (OData) を実装するデータ サービスを LINQ で照会する場合の制限について説明します。OData ベースのデータ サービスに対するクエリの作成および実行詳細情報、「データ サービスのクエリ (WCF Data Services)」を参照してください。

LINQ クエリの作成

LINQ を使用すると、IEnumerable を実装するオブジェクトのコレクションに対するクエリを作成できます。Visual Studio の [サービス参照の追加] ダイアログ ボックスと DataSvcUtil.exe ツールでは、DataServiceContext を継承するエンティティ コンテナー クラスとしての OData サービスの表現や、フィードで返されるエンティティを表すオブジェクトを生成できます。これらのツールでは、サービスによってフィードとして公開されるコレクションに対応するエンティティ コンテナー クラスのプロパティも生成されます。データ サービスをカプセル化するクラスのこれらのプロパティは、それぞれ DataServiceQuery を返します。DataServiceQuery クラスは LINQ で定義された IQueryable インターフェイスを実装するので、データ サービスによって公開されるフィードに対する LINQ クエリを作成できます。作成した LINQ クエリは、クライアント ライブラリにより、実行時にデータ サービスに送信されるクエリ要求 URI に変換されます。

Ee622463.Important(ja-jp,VS.100).gif 注 :
LINQ 構文で表現できるクエリのセットは、OData データ サービスによって使用される URI 構文で有効なクエリのセットよりも範囲が広くなります。クエリを対象データ サービスの URI にマップできない場合、NotSupportedException が発生します。詳細については、次のトピックを参照してください。、このトピックの「Unsupported LINQ Methods」を参照してください。

次の例の 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

LINQ 全般の詳細については、「Language-Integrated Query (LINQ)」を参照してください。

LINQ を使用してクエリを作成する際には、前の例のような言語固有の宣言型のクエリ構文と、標準クエリ演算子と呼ばれる一連のクエリ メソッドの両方を使用できます。したがって、次の例のように、前の例と同等のクエリをメソッド ベースの構文のみを使用して作成することもできます。

Dim selectedOrders = context.Orders _
                     .Where(Function(o) o.Freight.Value > 30) _
                     .OrderByDescending(Function(o) o.ShippedDate)
var selectedOrders = context.Orders
                    .Where(o => o.Freight > 30)
                    .OrderByDescending(o => o.ShippedDate);

どちらの方法で作成したクエリも、WCF Data Services クライアントによってクエリ URI に変換されます。クエリ式にクエリ メソッドを追加して LINQ クエリを拡張することもできます。クエリ式または DataServiceQuery にメソッド構文を追加して LINQ クエリを作成した場合は、メソッドが呼び出される順序で操作がクエリ URI に追加されます。これは、AddQueryOption メソッドを呼び出して各クエリ オプションをクエリ URI に追加するのと同じです。

LINQ クエリの実行

クエリに特定の LINQ クエリ メソッド (FirstSingle など) を追加するとクエリが実行されます。クエリは、結果が暗黙的に列挙される場合 (foreach ループの間など) や、クエリが List コレクションに割り当てられている場合にも実行されます。詳細については、「データ サービスのクエリ (WCF Data Services)」を参照してください。

クライアントによる LINQ クエリの実行は 2 つの部分に分かれています。可能な限り、クエリ内の LINQ 式は最初にクライアントで評価されます。その後、URI ベースのクエリが生成され、データ サービスに送信されて、サービス内のデータに対して評価されます。詳細については、「データ サービスのクエリ (WCF Data Services)」の「Client versus Server Execution」を参照してください。

OData 準拠のクエリ URI で LINQ クエリを変換できない場合は、クエリを実行しようとすると例外が発生します。詳細については、「データ サービスのクエリ (WCF Data Services)」を参照してください。

LINQ クエリの例

以下のセクションの各例は、OData サービスに対して実行できる LINQ クエリの種類を示しています。

フィルター処理

このセクションの LINQ クエリは、サービスによって返されるフィード内のデータをフィルター処理します。

以下の各例は、返された Orders エンティティをフィルター処理して、輸送費が 30 ドルを超える注文のみが返されるようにする同等のクエリを示しています。

  • LINQ クエリ構文を使用する場合:

    Dim filteredOrders = From o In context.Orders
                            Where o.Freight.Value > 30
                            Select o
    
    var filteredOrders = from o in context.Orders
                            where o.Freight > 30
                            select o;
    
  • LINQ クエリ メソッドを使用する場合:

    Dim filteredOrders = context.Orders.Where(Function(o) o.Freight.Value > 0)
    
    var filteredOrders = context.Orders
        .Where(o => o.Freight > 30);
    
  • URI クエリ文字列オプション $filter:

    ' Define a query for orders with a Freight value greater than 30.
    Dim filteredOrders _
                = context.Orders.AddQueryOption("$filter", "Freight gt 30M")
    
    // Define a query for orders with a Freight value greater than 30.
    var filteredOrders
        = context.Orders.AddQueryOption("$filter", "Freight gt 30M");
    

上の例はすべて、https://localhost:12345/northwind.svc/Orders()?$filter=Freight gt 30M というクエリ URI に変換されます。

並べ替え

以下の各例は、返されたデータを会社名と郵便番号の降順で並べ替える同等のクエリを示しています。

  • LINQ クエリ構文を使用する場合:

    Dim sortedCustomers = From c In context.Customers
                                 Order By c.CompanyName Ascending,
                                 c.PostalCode Descending
                                 Select c
    
    var sortedCustomers = from c in context.Customers
                         orderby c.CompanyName ascending, 
                         c.PostalCode descending
                         select c;
    
  • LINQ クエリ メソッドを使用する場合:

    Dim sortedCustomers = context.Customers.OrderBy(Function(c) c.CompanyName) _
    .ThenByDescending(Function(c) c.PostalCode)
    
    var sortedCustomers = context.Customers.OrderBy(c => c.CompanyName)
        .ThenByDescending(c => c.PostalCode);
    
  • URI クエリ文字列オプション $orderby:

    Dim sortedCustomers = context.Customers _
                          .AddQueryOption("$orderby", "CompanyName, PostalCode desc")
    
    var sortedCustomers = context.Customers
        .AddQueryOption("$orderby", "CompanyName, PostalCode desc");
    

上の例はすべて、https://localhost:12345/northwind.svc/Customers()?$orderby=CompanyName,PostalCode desc というクエリ URI に変換されます。

射影

以下の各例は、返されたデータをより範囲の狭い CustomerAddress 型に射影する同等のクエリを示しています。

  • LINQ クエリ構文を使用する場合:

    Dim projectedQuery = From c In context.Customers
                         Select New CustomerAddress With
                        {
                            .CustomerID = c.CustomerID,
                            .Address = c.Address,
                            .City = c.City,
                            .Region = c.Region,
                            .PostalCode = c.PostalCode,
                            .Country = c.Country
                        }
    
    var projectedQuery = from c in context.Customers
                select new CustomerAddress
                {
                    CustomerID = c.CustomerID,
                    Address = c.Address,
                    City = c.City,
                    Region = c.Region,
                    PostalCode = c.PostalCode,
                    Country = c.Country
                };
    
  • LINQ クエリ メソッドを使用する場合:

    Dim projectedQuery = context.Customers.Where(Function(c) c.Country = "Germany") _
                .Select(Function(c) New CustomerAddress With
                {
                    .CustomerID = c.CustomerID,
                    .Address = c.Address,
                    .City = c.City,
                    .Region = c.Region,
                    .PostalCode = c.PostalCode,
                    .Country = c.Country
                })
    
    var projectedQuery = context.Customers.Where(c => c.Country == "Germany")
        .Select(c => new CustomerAddress
        {
            CustomerID = c.CustomerID, 
            Address = c.Address,
            City = c.City,
            Region = c.Region,
            PostalCode = c.PostalCode,
            Country = c.Country});                   
    
Ee622463.note(ja-jp,VS.100).gif注 :
AddQueryOption メソッドを使用してクエリ URI に $select クエリ オプションを追加することはできません。LINQ の Select メソッドを使用して、クライアントによって要求 URI に $select クエリ オプションが生成されるようにすることをお勧めします。

上の例はいずれも、"https://localhost:12345/northwind.svc/Customers()?$filter=Country eq 'GerGerm'&$select=CustomerID,Address,City,Region,PostalCode,Country" というクエリ URI に変換されます。

クライアントのページング

以下の各例は、25 件の注文を含む並べ替え済みの注文エンティティのページを、最初の 50 件の注文をスキップして要求する同等のクエリを示しています。

  • LINQ クエリにクエリ メソッドを適用する場合:

    Dim pagedOrders = (From o In context.Orders
                       Order By o.OrderDate Descending
                       Select o) _
                   .Skip(50).Take(25)
    
    var pagedOrders = (from o in context.Orders
                          orderby o.OrderDate descending
                         select o).Skip(50).Take(25);
    
  • URI クエリ文字列オプション $skip および $top:

    Dim pagedOrders = context.Orders _
                      .AddQueryOption("$orderby", "OrderDate desc") _
                      .AddQueryOption("$skip", 50) _
                      .AddQueryOption("$top", 25) _
    
    var pagedOrders = context.Orders
        .AddQueryOption("$orderby", "OrderDate desc")
        .AddQueryOption("$skip", 50)
        .AddQueryOption("$top", 25);
    

上の例はいずれも、https://localhost:12345/northwind.svc/Orders()?$orderby=OrderDate desc&$skip=50&$top=25 というクエリ URI に変換されます。

展開

OData データ サービスを照会するときに、返されるフィードにクエリの対象のエンティティに関連するエンティティを含めるように要求することができます。そのためには、LINQ クエリの対象のエンティティ セットの DataServiceQueryExpand メソッドを呼び出して、関連するエンティティ セットの名前を path パラメーターとして渡します。詳細については、「遅延コンテンツの読み込み (WCF Data Services)」を参照してください。

以下の各例は、クエリで Expand メソッドを使用する同等の方法を示しています。

  • LINQ クエリ構文の場合:

    Dim ordersQuery = From o In context.Orders.Expand("Order_Details")
                         Where o.CustomerID = "ALFKI"
                         Select o
    
    var ordersQuery = from o in context.Orders.Expand("Order_Details")
                         where o.CustomerID == "ALFKI"
                         select o;
    
  • LINQ クエリ メソッドの場合:

    Dim ordersQuery = context.Orders.Expand("Order_Details") _
                              .Where(Function(o) o.CustomerID = "ALFKI")
    
    var ordersQuery = context.Orders.Expand("Order_Details")
                      .Where(o => o.CustomerID == "ALFKI");
    

上の例はいずれも、https://localhost:12345/northwind.svc/Orders()?$filter=CustomerID eq 'ALFKI'&$expand=Order_Details というクエリ URI に変換されます。

サポートされていない LINQ メソッド

次の表に含まれている LINQ メソッドはサポートされていません。OData サービスに対して実行されるクエリにこれらのメソッドを含めることはできません。

演算の種類  サポートされていないメソッド

集合演算子

すべての集合演算子は DataServiceQuery に対してサポートされていません。以下に例を示します。

順序付け演算子

IComparer を必要とする以下の順序付け演算子は DataServiceQuery に対してサポートされていません。

プロジェクション演算子とフィルター演算子

位置指定引数を受け取る以下のプロジェクション演算子とフィルター演算子は DataServiceQuery に対してサポートされていません。

グループ化演算子

すべてのグループ化演算子は DataServiceQuery に対してサポートされていません。以下に例を示します。

グループ化の操作はクライアント側で実行する必要があります。

集計演算子

すべての集計演算子は DataServiceQuery に対してサポートされていません。以下に例を示します。

集計操作は、クライアント側で実行するか、サービス操作でカプセル化する必要があります。

ページング演算子

以下のページング演算子は DataServiceQuery に対してサポートされていません。

Ee622463.note(ja-jp,VS.100).gif注 :
空シーケンスで実行されるページング演算子は null を返します。

その他の演算子

以下に示す演算子は DataServiceQuery に対してサポートされていません。

  1. Empty

  2. Range

  3. Repeat

  4. ToDictionary

  5. ToLookup

サポートされている式の関数

共通言語ランタイム (CLR) の以下のメソッドおよびプロパティは、クエリ式で変換して OData サービスへの要求 URI に含めることができるため、サポートされています。

String メンバー サポートされている OData 関数

Concat

string concat(string p0, string p1)

Contains

bool substringof(string p0, string p1)

EndsWith

bool endswith(string p0, string p1)

IndexOf

int indexof(string p0, string p1)

Length

int length(string p0)

Replace

string replace(string p0, string find, string replace)

Substring

string substring(string p0, int pos)

Substring

string substring(string p0, int pos, int length)

ToLower

string tolower(string p0)

ToUpper

string toupper(string p0)

Trim

string trim(string p0)

DateTime メンバー1 サポートされている OData 関数

Day

int day(DateTime p0)

Hour

int hour(DateTime p0)

Minute

int minute(DateTime p0)

Month

int month(DateTime p0)

Second

int second(DateTime p0)

Year

int year(DateTime p0)

1 Microsoft.VisualBasic.DateAndTime の同等の日時プロパティと Visual Basic の DatePart メソッドもサポートされています。

Math メンバー サポートされている OData 関数

Ceiling

decimal ceiling(decimal p0)

Ceiling

double ceiling(double p0)

Floor

decimal floor(decimal p0)

Floor

double floor(double p0)

Round

decimal round(decimal p0)

Round

double round(double p0)

Expression メンバー サポートされている OData 関数

TypeIs

bool isof(type p0)

クライアント側でその他の CLR 関数を評価できる場合もあります。クライアント側で評価することも、サーバー側で評価するために有効な要求 URI に変換することもできない式に対しては、NotSupportedException が発生します。

参照

概念

データ サービスのクエリ (WCF Data Services)
クエリ射影 (WCF Data Services)
オブジェクトの具体化 (WCF Data Services)

その他のリソース

OData: URI 規則に関する Web ページ