LINQ から SQL への変換

適用対象: NoSQL

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

上記の演算子を組み合わせて、より強力なクエリを作成できます。 Azure 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
    

次のステップ