次の方法で共有


標準クエリ演算子の変換

LINQ to SQL では、標準クエリ演算子が SQL コマンドに変換されます。 データベースのクエリ プロセッサによって、SQL 変換の実行セマンティクスが決まります。

標準クエリ演算子は、シーケンスに対して定義 されます。 シーケンスは 順序付け され、シーケンスの各要素の参照 ID に依存します。 詳細については、「 標準クエリ演算子の概要 (C#) 」または 「標準クエリ演算子の概要 (Visual Basic)」を参照してください。

SQL では、主に 順序指定されていない値のセットが処理されます。 順序付けは、通常、中間結果ではなく、クエリの最終結果に適用される明示的に記述された後処理操作です。 ID は値によって定義されます。 このため、SQL クエリは、セットではなくマルチセット (バッグ) を処理すると認識されます。

次の段落では、標準クエリ演算子と、LINQ to SQL 用 SQL Server プロバイダーの SQL 変換の違いについて説明します。

オペレーターのサポート

Concat

Concatメソッドは、受信側の順序と引数の順序が同じ順序のマルチセットに対して定義されます。 Concat は、マルチセットの後に共通の順序が続く UNION ALL として機能します。

最後の手順は、結果が生成される前に SQL で並べ替えます。 Concat では、引数の順序は保持されません。 適切な順序を確保するには、 Concatの結果を明示的に並べ替える必要があります。

Intersect、Except、Union

IntersectメソッドとExcept メソッドは、セットでのみ明確に定義されます。 マルチセットのセマンティクスは未定義です。

Unionメソッドは、マルチセットの順序なし連結としてマルチセットに対して定義されます (実質的には、SQL の UNION ALL 句の結果)。

Take、Skip

Take メソッドと Skip メソッドは、 順序付けられたセットに対してのみ明確に定義されます。 順序指定されていないセットまたはマルチセットのセマンティクスは未定義です。

Take SQL Server 2000 に対するクエリで使用される場合、 Skip には特定の制限があります。 詳細については、「トラブルシューティング」の「SQL Server 2000 のスキップと例外の取り込み」エントリ 参照してください。

SQL での順序付けには制限があるため、LINQ to SQL は、これらのメソッドの引数の順序をメソッドの結果に移動しようとします。 たとえば、次の LINQ to SQL クエリを考えてみましょう。

var custQuery =
    (from cust in db.Customers
    where cust.City == "London"
    orderby cust.CustomerID
    select cust).Skip(1).Take(1);
Dim custQuery = _
    From cust In db.Customers _
    Where cust.City = "London" _
    Order By cust.CustomerID _
    Select cust Skip 1 Take 1

このコードに対して生成された SQL は、次のように順序を末尾に移動します。

SELECT TOP 1 [t0].[CustomerID], [t0].[CompanyName],
FROM [Customers] AS [t0]
WHERE (NOT (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM (
        SELECT TOP 1 [t1].[CustomerID]
        FROM [Customers] AS [t1]
        WHERE [t1].[City] = @p0
        ORDER BY [t1].[CustomerID]
        ) AS [t2]
    WHERE [t0].[CustomerID] = [t2].[CustomerID]
    ))) AND ([t0].[City] = @p1)
ORDER BY [t0].[CustomerID]

TakeSkipが連結されている場合、指定されたすべての順序が一貫している必要があることは明らかになります。 それ以外の場合、結果は未定義です。

TakeSkipはどちらも、標準クエリ演算子の仕様に基づいて、負でない定数整数引数に対して明確に定義されています。

変換なしの演算子

次のメソッドは、LINQ to SQL では変換されません。 最も一般的な理由は、順序付けられていないマルチセットとシーケンスの違いです。

オペレーター 理由
TakeWhileSkipWhile SQL クエリは、シーケンスではなくマルチセットで動作します。 ORDER BY は、結果に適用される最後の句である必要があります。 このため、これら 2 つのメソッドには汎用の翻訳はありません。
Reverse 順序付きセットでは、このメソッドの変換は可能ですが、現在 LINQ to SQL では変換されていません。
LastLastOrDefault これらのメソッドの変換は順序付けされたセットに対して可能ですが、現在 LINQ to SQL では変換されていません。
ElementAtElementAtOrDefault SQL クエリは、インデックス可能なシーケンスではなく、マルチセットで動作します。
DefaultIfEmpty (既定の arg を使用したオーバーロード) 一般に、任意のタプルに既定値を指定することはできません。 タプルの null 値は、場合によっては外部結合によって可能です。

式の翻訳

NULL セマンティクス

LINQ to SQL では、SQL に null 比較セマンティクスは適用されません。 比較演算子は、構文的に SQL に相当するものに変換されます。 このため、セマンティクスには、サーバーまたは接続の設定で定義されている SQL セマンティクスが反映されます。 たとえば、既定の SQL Server 設定では 2 つの null 値が等しくないと見なされますが、設定を変更してセマンティクスを変更できます。 LINQ to SQL では、クエリを変換するときにサーバー設定は考慮されません。

リテラル null との比較は、適切な SQL バージョン (is null または is not null) に変換されます。

照合順序の null の値は、SQL Server によって定義されます。 LINQ to SQL では照合順序は変更されません。

集合体

標準クエリ演算子集計メソッド Sum 、空のシーケンスまたは null のみを含むシーケンスの場合は 0 に評価されます。 LINQ to SQL では、SQL のセマンティクスは変更されず、 Sum は空のシーケンスまたは null のみを含むシーケンスに対して 0 ではなく、 null に評価されます。

中間結果に対する SQL の制限は、LINQ to SQL の集計に適用されます。 32 ビット整数の Sum は、64 ビットの結果を使用して計算されません。 標準クエリ演算子の実装で対応するメモリ内シーケンスのオーバーフローが発生しない場合でも、LINQ to SQL による Sumの変換でオーバーフローが発生する可能性があります。

同様に、整数値のAverageの LINQ to SQL 変換は、doubleとしてではなく、integerとして計算されます。

Entity 引数

LINQ to SQL を使用すると、 GroupBy メソッドと OrderBy メソッドでエンティティ型を使用できます。 これらの演算子の変換では、型の引数の使用は、その型のすべてのメンバーを指定することと同等と見なされます。 たとえば、次のコードは同等です。

db.Customers.GroupBy(c => c);
db.Customers.GroupBy(c => new { c.CustomerID, c.ContactName });
db.Customers.GroupBy(Function(c) c)
db.Customers.GroupBy(Function(c) New With {c.CustomerID, _
    c.ContactName})

等値可能/比較可能な引数

次のメソッドの実装では、引数の等価性が必要です。

LINQ to SQL では 、フラット 引数の等価性と比較はサポートされていますが、シーケンスである引数またはシーケンスを含む引数の場合はサポートされません。 フラット引数は、SQL 行にマップできる型です。 シーケンスを含まないと静的に判断できる 1 つ以上のエンティティ型の射影は、フラット引数と見なされます。

フラット引数の例を次に示します。

db.Customers.Select(c => c);
db.Customers.Select(c => new { c.CustomerID, c.City });
db.Orders.Select(o => new { o.OrderID, o.Customer.City });
db.Orders.Select(o => new { o.OrderID, o.Customer });	
db.Customers.Select(Function(c) c)
db.Customers.Select(Function(c) New With {c.CustomerID, c.City})
db.Orders.Select(Function(o) New With {o.OrderID, o.Customer.City})
db.Orders.Select(Function(o) New With {o.OrderID, o.Customer})

非フラット (階層) 引数の例を次に示します。

// In the following line, c.Orders is a sequence.
db.Customers.Select(c => new { c.CustomerID, c.Orders });
// In the following line, the result has a sequence.
db.Customers.GroupBy(c => c.City);
' In the following line, c.Orders is a sequence.
db.Customers.Select(Function(c) New With {c.CustomerID, c.Orders})
' In the following line, the result has a sequence.
db.Customers.GroupBy(Function(c) c.City)

Visual Basic 関数の翻訳

Visual Basic コンパイラで使用される次のヘルパー関数は、対応する SQL 演算子と関数に変換されます。

  • CompareString

  • DateTime.Compare

  • Decimal.Compare

  • IIf (in Microsoft.VisualBasic.Interaction)

変換方法:

  • ToBoolean
  • ToSByte
  • ToByte
  • ToChar
  • ToCharArrayRankOne
  • ToDate
  • ToDecimal
  • ToDouble
  • ToInteger
  • ToUInteger
  • ToLong
  • ToULong
  • ToShort
  • ToUShort
  • ToSingle
  • ToString

継承のサポート

継承マッピングの制限

詳細については、「 方法: 継承階層をマップする」を参照してください。

クエリでの継承

C# キャストはプロジェクションでのみサポートされます。 他の場所で使用されるキャストは変換されず、無視されます。 SQL 関数名とは別に、SQL は実際には共通言語ランタイム (CLR) Convertと同等の機能のみを実行します。 つまり、SQL では、ある型の値を別の型に変更できます。 別の型と同じビットを再解釈する概念がないため、CLR キャストに相当するものはありません。 そのため、C# キャストはローカルでのみ機能します。 リモートではありません。

演算子、 isas、および GetType メソッドは、 Select 演算子に限定されません。 他のクエリ演算子でも使用できます。

SQL Server 2008 のサポート

.NET Framework 3.5 SP1 以降、LINQ to SQL では、SQL Server 2008 で導入された新しい日付と時刻の型へのマッピングがサポートされています。 ただし、LINQ to SQL クエリ演算子には、これらの新しい型にマップされた値に対して操作するときに使用できるいくつかの制限があります。

サポートされていないクエリ演算子

新しい SQL Server の日付と時刻の種類にマップされた値 ( DATETIME2DATETIMEDATETIMEOFFSET) では、次のクエリ演算子はサポートされていません。

  • Aggregate

  • Average

  • LastOrDefault

  • OfType

  • Sum

これらの SQL Server の日付と時刻型へのマッピングの詳細については、「 SQL-CLR 型マッピング」を参照してください。

SQL Server 2005 のサポート

LINQ to SQL では、次の SQL Server 2005 機能はサポートされていません。

  • SQL CLR 用に記述されたストアド プロシージャ。

  • ユーザー定義型。

  • XML クエリ機能。

SQL Server 2000 のサポート

次の SQL Server 2000 の制限 (Microsoft SQL Server 2005 と比較) は、LINQ to SQL のサポートに影響します。

クロス アプライ演算子と外部アプライ演算子

これらの演算子は、SQL Server 2000 では使用できません。 LINQ to SQL では、一連の書き換えを試みて、適切な結合に置き換えます。

Cross ApplyOuter Apply はリレーションシップ ナビゲーション用に生成されます。 このような書き換えが可能なクエリのセットが明確に定義されていません。 このため、SQL Server 2000 でサポートされるクエリの最小セットは、リレーションシップ ナビゲーションを含まないセットです。

text / ntext

text / ntextデータ型は、Microsoft SQL Server 2005 でサポートされているvarchar(max) / nvarchar(max)に対する特定のクエリ操作では使用できません。

この制限に対する解決策はありません。 具体的には、text列またはntext列にマップされているメンバーを含む結果に対してDistinct()を使用することはできません。

入れ子になったクエリによってトリガーされる動作

SQL Server 2000 (SP4 経由) バインダーには、入れ子になったクエリによってトリガーされるいくつかの特異点があります。 これらの特異性をトリガーする SQL クエリのセットが明確に定義されていません。 このため、SQL Server の例外を引き起こす可能性がある LINQ to SQL クエリのセットを定義することはできません。

Skip 演算子と Take 演算子

Take SQL Server 2000 に対するクエリで使用される場合、 Skip には特定の制限があります。 詳細については、「トラブルシューティング」の「SQL Server 2000 のスキップと例外の取り込み」エントリ 参照してください。

オブジェクトの具体化

具体化では、1 つ以上の SQL クエリによって返される行から CLR オブジェクトが作成されます。

  • 次の呼び出しは、具体化の一環として ローカルで実行されます

    • コンストラクター

    • ToString プロジェクションのメソッド

    • プロジェクションでの型キャスト

  • AsEnumerable メソッドに続くメソッドはローカルで実行されます。 このメソッドでは、すぐに実行されることはありません。

  • クエリ結果の戻り値の型として、または結果の型のメンバーとして、 struct を使用できます。 エンティティはクラスである必要があります。 匿名型はクラス インスタンスとして具体化されますが、プロジェクションでは名前付き構造体 (非エンティティ) を使用できます。

  • クエリ結果の戻り値の型のメンバーは、 IQueryable<T>型にすることができます。 これはローカル コレクションとして具体化されます。

  • 次のメソッドを使用すると、メソッドが適用されるシーケンスが 即時に具体化 されます。

こちらも参照ください