В чем разница между этими двумя операторами LINQtoSQL? - PullRequest
5 голосов
/ 23 декабря 2009

Эти два оператора выглядят одинаково логически для меня, но они приводят к генерированию другого 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 в запросе final отличается следующим образом:

#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)
    )

Почему эта разница?

Edit:

До сих пор все, что я делал, чтобы получить сгенерированный SQL, - это проверка запрашиваемого в отладчике. Однако после настройки логгера, как предложил Джон, кажется, что real 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]

Ответы [ 2 ]

1 голос
/ 23 декабря 2009

Во-первых, подумайте о двойственной природе 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());

Во втором примере C # преобразовал Enum в строку, поэтому преобразование не требуется, и предполагается, что столбец People.Status вашей базы данных принимает строки "STUDENT", "TEACHER", "DIRECTOR" в качестве допустимых значений в логике.

Разница в том, что внутреннее представление enum в CLR является целым числом, а в первом примере параметр @p передается как целое число, это поведение построителя запросов L2S, поэтому преобразование.

Первый из них сработал бы, если бы в моем примере столбец базы данных представлял собой int, принимающий значения, назначенные членам Enum {1,2,10}.

1 голос
/ 23 декабря 2009

Нет, они разные. В первой версии выражение MyPersonEnum.STUDENT.ToString() находится внутри дерева выражений - это часть того, что LINQ to SQL должен преобразовать в SQL. Мне было бы интересно посмотреть, что означает @p0 при выполнении запроса ...

Во второй версии вы уже оценили выражение, поэтому LINQ to SQL просто видит ссылку на переменную, которая уже является строкой.

Мы знаем, что они имеют в виду одно и то же, но, по-видимому, LINQ to SQL не имеет достаточно знаний, чтобы понять это.

Из интереса, они оба работают?

РЕДАКТИРОВАТЬ: Хорошо, так что вторая версия работает. Я предлагаю вам использовать эту форму тогда :) В идеальном мире оба будут работать - но в этом случае, похоже, вам нужно немного помочь LINQ to SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...