5

これらの 2 つのステートメントは論理的には同じように見えますが、異なる SQL が生成されます。

#1 
var people = _DB.People.Where(p => p.Status == MyPersonEnum.STUDENT.ToString());
var ids = people.Select(p => p.Id);
var cars = _DB.Cars.Where(c => ids.Contains(c.PersonId));

#2 
string s = MyPersonEnum.STUDENT.ToString();
var people = _DB.People.Where(p => p.Status == s);
var ids = people.Select(p => p.Id);
var cars = _DB.Cars.Where(c => ids.Contains(c.PersonId));

例 #1 は機能しませんが、例 #2 は機能します。

クエリ用に生成された SQL はvar people両方で同じですが、最終的なクエリの SQL は次のように異なります。

#1
SELECT [t0].[PersonId], [t0].[etc].....
FROM [Cars] AS [t0]
WHERE EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [People] AS [t1]
    WHERE ([t1].[Id] = [t0].[PersonId]) AND ([t1].[Status] = (CONVERT(NVarChar,@p0)))
    )

#2
SELECT [t0].[PersonId], [t0].[etc].....
FROM [Cars] AS [t0]
WHERE EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [People] AS [t1]
    WHERE ([t1].[Id] = [t0].[PersonId]) AND ([t1].[Status] = @p0)
    )

なぜこの違いがあるのですか?

編集:

これまで、生成された SQL を取得するために行ったことは、デバッガーでクエリ可能なものを検査することだけでした。ただし、Jon が提案したようにロガーを設定した後、実行された実際のsql は異なるようです。

#1 
SELECT [t1].[Id], [t1].etc ... [t0].Id, [t1].etc ...
FROM [Cars] AS [t0], [People] AS [t1]
WHERE ([t1].[Id] = [t0].[PersonId]) AND (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [People] AS [t2]
    WHERE ([t2].[Id] = [t0].[PersonId]) AND ([t2].[Status] = (CONVERT(NVarChar,@p0)))
    )) AND ([t1].[Status] = @p1)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- @p1: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [STUDENT]

#2
SELECT [t1].[Id], [t1].etc ... [t0].Id, [t1].etc ...
FROM [Cars] AS [t0], [People] AS [t1]
WHERE ([t1].[Id] = [t0].[PersonId]) AND (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [People] AS [t2]
    WHERE ([t2].[Id] = [t0].[PersonId]) AND ([t2].[Status] = @p0)
    )) AND ([t1].[Status] = @p1)
-- @p0: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [STUDENT]
-- @p1: Input NVarChar (Size = 7; Prec = 0; Scale = 0) [STUDENT]
4

2 に答える 2

1

まず、e Enum の二重性について考えてみましょう。

enum MyPersonEnum
{
  STUDENT, // implicit 1
  TEACHER, // implicit 2
  DIRECTOR = 10 // explicit 10
}

...

Assert.AreEqual(1, (int)MyPersonEnum.STUDENT);
Assert.AreEqual("STUDENT", MyPersonEnum.STUDENT.ToString());

2 番目の例では、C# は Enum を文字列に変換したため、変換は必要ありません。また、データベースの People.Status 列が "STUDENT"、"TEACHER"、"DIRECTOR" の文字列をロジックの有効な値として受け入れると想定しています。

違いは、CLR の enum 内部表現が整数であり、最初の例である @p パラメータが整数として渡されることです。これは L2S クエリ ビルダーの動作であり、それが変換の理由です。

データベースの列が、私の例で Enum メンバー {1,2,10} に割り当てられた値を取る int である場合、最初のものは機能します。

于 2009-12-23T18:14:27.650 に答える