Share via


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

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

このトピックは、次のセクションで構成されています。

LINQ クエリの作成

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

重要

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<TElement> にメソッド構文を追加して LINQ クエリを作成した場合は、メソッドが呼び出される順序で操作がクエリ URI に追加されます。 これは、AddQueryOption(String, Object) メソッドを呼び出して各クエリ オプションをクエリ URI に追加するのと同じです。

LINQ クエリの実行

クエリに特定の LINQ クエリ メソッド (First<TSource>Single<TSource> など) を追加するとクエリが実行されます。 クエリは、結果が暗黙的に列挙される場合 (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 に変換されます。

All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) および Any<TSource>(IEnumerable<TSource>) 演算子を使用し、コレクション プロパティに基づいてくエンティティをフィルター処理するクエリを作成することもできます。 この場合、述語は関連エンティティのコレクションとプリミティブ型および複合型のコレクションの両方を返すプロパティに対して評価されます。 たとえば、次のクエリでは指定された文字列を含む説明付きの領域を持つ従業員を返します。

Dim filteredEmployees = From e In context.Employees _
                        Where e.Territories.Any(Function(t) t.TerritoryDescription.Contains(territory))
                        Select e
var filteredEmployees = from e in context.Employees
                        where e.Territories.Any(t => t.TerritoryDescription.Contains(territory))
                        select e;

このクエリでは、Any<TSource>(IEnumerable<TSource>) 演算子を使用して Employees と Territories 間で多対多のアソシエーションを走査し、関連領域の評価に基づいて従業員をフィルター処理できます。 詳細については、投稿の「WCF Data Services での Any/All のサポート」を参照してください。

並べ替え

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

  • 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});                   
    

注意

AddQueryOption(String, Object) メソッドを使用してクエリ URI に $select クエリ オプションを追加することはできません。LINQ の Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) メソッドを使用して、クライアントによって要求 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 クエリの対象のエンティティ セットの DataServiceQuery<TElement>Expand(String) メソッドを呼び出して、関連するエンティティ セットの名前を path パラメーターとして渡します。 詳細については、「遅延コンテンツの読み込み (WCF Data Services)」を参照してください。

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

  • 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<TElement> に対してサポートされていません。

順序付け演算子

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

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

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

グループ化演算子

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

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

集計演算子

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

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

ページング演算子

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

注意

空シーケンスで実行されるページング演算子は null を返します。

その他の演算子

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

  1. Empty<TResult>

  2. Range

  3. Repeat<TResult>

  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)

1Microsoft.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 が発生します。

バージョン管理の要件

LINQ サポートには、次に示す OData プロトコルのバージョン管理の要件があります。

詳細については、「データ サービスのバージョン管理 (WCF Data Services)」を参照してください。

関連項目

概念

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

クエリ射影 (WCF Data Services)

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

その他の技術情報

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