LINQ から SQL への変換

適用対象: SQL API

Azure Cosmos DB クエリ プロバイダーは、LINQ クエリから Cosmos DB SQL クエリへのマッピングをベスト エフォートで実行します。 LINQ から変換される SQL クエリを取得する場合、生成された IQueryable オブジェクトで ToString() メソッドを使用します。 以下の説明では、LINQ の基本的知識を前提としています。 LINQ に加えて、Azure Cosmos DB では、SQL API と連携する Entity Framework Core もサポートされます。

Note

最新の .NET SDK バージョンを使用することをお勧めします。

クエリ プロバイダーの型システムでは、JSON プリミティブ型 (数値型、ブール値、文字列、null) のみがサポートされます。

クエリ プロバイダーでは、以下のスカラー式がサポートされます。

  • 定数値。クエリ評価時のプリミティブ データ型の定数値を含みます。

  • プロパティ/配列インデックス式。オブジェクトまたは配列要素のプロパティを参照します。 次に例を示します。

      family.Id;
      family.children[0].familyName;
      family.children[0].grade;
      family.children[n].grade; //n is an int variable
    
  • 算術式。数値およびブール値に対する共通の算術式を含みます。 完全な一覧については、Azure Cosmos DB SQL の仕様に関するページを参照してください。

      2 * family.children[0].grade;
      x + y;
    
  • 文字列比較式。これは、文字列値と定数文字列値との比較を含みます。

      mother.familyName == "Wakefield";
      child.givenName == s; //s is a string variable
    
  • オブジェクト/配列作成式。複合値の型または匿名型のオブジェクト、またはこうしたオブジェクトの配列を返します。 これらの値は入れ子にすることができます。

      new Parent { familyName = "Wakefield", givenName = "Robin" };
      new { first = 1, second = 2 }; //an anonymous type with two fields  
      new int[] { 3, child.grade, 5 };
    

LINQ を使用する

GetItemLinqQueryable を使用して LINQ クエリを作成できます。 この例では、FeedIterator を使用した LINQ クエリの生成と非同期実行を示します。

using (FeedIterator<Book> setIterator = container.GetItemLinqQueryable<Book>()
                      .Where(b => b.Title == "War and Peace")
                      .ToFeedIterator<Book>())
 {
     //Asynchronous query execution
     while (setIterator.HasMoreResults)
     {
         foreach(var item in await setIterator.ReadNextAsync()){
         {
             Console.WriteLine(item.cost);
         }
       }
     }
 }

サポートされている LINQ 演算子

SQL .NET SDK に含まれる LINQ プロバイダーでは、次の演算子がサポートされています。

  • Select:オブジェクトの構築など、プロジェクションによって SELECT に変換します。
  • Where:フィルターによって WHERE に変換します。また、&&||、および ! から SQL 演算子への変換をサポートしています
  • SelectMany:JOIN 句に対して配列をアンワインドできます。 配列要素に関してフィルターする式を連結または入れ子にするために使用します。
  • OrderByOrderByDescending:ASC または DESC で ORDER BY に変換します。
  • 集計のための CountSumMinMaxAverage 演算子と非同期でそれに相当する CountAsyncSumAsyncMinAsyncMaxAsyncAverageAsync 演算子。
  • CompareTo:範囲比較に変換します。 .NET では比較できないので、一般的に文字列に使用されます。
  • SkipTake:クエリからの結果を制限して改ページ位置の自動修正を実行するために、OFFSET および LIMIT に変換されます。
  • 数学関数:.NET AbsAcosAsinAtanCeilingCosExpFloorLogLog10PowRoundSignSinSqrtTan、および Truncate から同等の組み込み数学関数への変換をサポートします。
  • 文字列関数:.NET ConcatContainsCountEndsWith,IndexOfReplaceReverseStartsWithSubStringToLowerToUpperTrimEnd、および TrimStart から同等の組み込み文字列関数への変換をサポートします。
  • 配列関数:.NET ConcatContains、および Count から同等の組み込み配列関数への変換をサポートします。
  • 地理空間の拡張関数:スタブ メソッド DistanceIsValidIsValidDetailed、および Within から同等の組み込み地理空間関数への変換をサポートします。
  • ユーザー定義関数の拡張関数: スタブ メソッド CosmosLinq.InvokeUserDefinedFunction から、対応するユーザー定義関数への変換をサポートします。
  • その他: Coalesce と条件演算子の変換をサポートします。 コンテキストに応じて、Contains から、文字列 CONTAINS、ARRAY_CONTAINS、または IN に変換できます。

一部の標準 LINQ クエリ演算子が Azure Cosmos DB のクエリにどのように変換されるかを以下の例で示します。

Select 演算子

構文は input.Select(x => f(x)) です。f はスカラー式です。 この場合、inputIQueryable オブジェクトになります。

Select 演算子、例 1:

  • LINQ ラムダ式

        input.Select(family => family.parents[0].familyName);
    
  • SQL

        SELECT VALUE f.parents[0].familyName
        FROM Families f
    

Select 演算子、例 2:

  • LINQ ラムダ式

        input.Select(family => family.children[0].grade + c); // c is an int variable
    
  • SQL

        SELECT VALUE f.children[0].grade + c
        FROM Families f
    

Select 演算子、例 3:

  • LINQ ラムダ式

      input.Select(family => new
      {
          name = family.children[0].familyName,
          grade = family.children[0].grade + 3
      });
    
  • SQL

        SELECT VALUE {"name":f.children[0].familyName,
                      "grade": f.children[0].grade + 3 }
        FROM Families f
    

SelectMany 演算子

構文は input.SelectMany(x => f(x)) です。f はコンテナー型を返すスカラー式です。

  • LINQ ラムダ式

        input.SelectMany(family => family.children);
    
  • SQL

        SELECT VALUE child
        FROM child IN Families.children
    

Where 演算子

構文は input.Where(x => f(x)) です。f は Boolean 値を返すスカラー式です。

Where 演算子、例 1:

  • LINQ ラムダ式

        input.Where(family=> family.parents[0].familyName == "Wakefield");
    
  • SQL

        SELECT *
        FROM Families f
        WHERE f.parents[0].familyName = "Wakefield"
    

Where 演算子、例 2:

  • LINQ ラムダ式

        input.Where(
            family => family.parents[0].familyName == "Wakefield" &&
            family.children[0].grade < 3);
    
  • SQL

        SELECT *
        FROM Families f
        WHERE f.parents[0].familyName = "Wakefield"
        AND f.children[0].grade < 3
    

複合 SQL クエリ

上記の演算子を組み合わせて、より強力なクエリを作成できます。 Cosmos DB では入れ子になったコンテナーがサポートされるため、複合を連結または入れ子にできます。

連結

構文は input(.|.SelectMany())(.Select()|.Where())*です。 連結クエリは、オプションの SelectMany クエリで開始し、複数の Select または Where 演算子を追加できます。

連結、例 1:

  • LINQ ラムダ式

        input.Select(family => family.parents[0])
            .Where(parent => parent.familyName == "Wakefield");
    
  • SQL

        SELECT *
        FROM Families f
        WHERE f.parents[0].familyName = "Wakefield"
    

連結、例 2:

  • LINQ ラムダ式

        input.Where(family => family.children[0].grade > 3)
            .Select(family => family.parents[0].familyName);
    
  • SQL

        SELECT VALUE f.parents[0].familyName
        FROM Families f
        WHERE f.children[0].grade > 3
    

連結、例 3:

  • LINQ ラムダ式

        input.Select(family => new { grade=family.children[0].grade}).
            Where(anon=> anon.grade < 3);
    
  • SQL

        SELECT *
        FROM Families f
        WHERE ({grade: f.children[0].grade}.grade > 3)
    

連結、例 4:

  • LINQ ラムダ式

        input.SelectMany(family => family.parents)
            .Where(parent => parents.familyName == "Wakefield");
    
  • SQL

        SELECT *
        FROM p IN Families.parents
        WHERE p.familyName = "Wakefield"
    

入れ子

構文は input.SelectMany(x=>x.Q()) です。QSelectSelectMany、または Where 演算子です。

入れ子になったクエリは、内側のクエリを外側のコンテナーの各要素に適用します。 1 つの重要な機能として、内側のクエリは外側のコンテナーの要素のフィールドを自己結合のように参照できます。

入れ子、例 1:

  • LINQ ラムダ式

        input.SelectMany(family=>
            family.parents.Select(p => p.familyName));
    
  • SQL

        SELECT VALUE p.familyName
        FROM Families f
        JOIN p IN f.parents
    

入れ子、例 2:

  • LINQ ラムダ式

        input.SelectMany(family =>
            family.children.Where(child => child.familyName == "Jeff"));
    
  • SQL

        SELECT *
        FROM Families f
        JOIN c IN f.children
        WHERE c.familyName = "Jeff"
    

入れ子、例 3:

  • LINQ ラムダ式

        input.SelectMany(family => family.children.Where(
            child => child.familyName == family.parents[0].familyName));
    
  • SQL

        SELECT *
        FROM Families f
        JOIN c IN f.children
        WHERE c.familyName = f.parents[0].familyName
    

次のステップ