LINQ возвращает 0 результатов, если используется переменная типа null - PullRequest
11 голосов
/ 10 февраля 2011

У меня есть таблица с именем «test», в которой есть только 1 столбец, «NullableInt» (тип nullable int)

Записи: 1, 2, null

int? nullableInt = null;
var t = db.tests.Where(x => x.NullableInt == null).ToList(); // returns 1 record
var t2 = db.tests.Where(x => x.NullableInt == nullableInt).ToList(); // returns 0 records

По какой-то причине t2 возвращает 0 записей, даже если он использует переменную "nullableInt", которая имеет значение null, как и t, который сравнивается с "null"

Любая помощь будет принята с благодарностью!

Ответы [ 5 ]

6 голосов
/ 10 февраля 2011

Да - это ошибка в LINQ-to-SQL / Entity Framework.IS NULL запросы будут генерироваться только в том случае, если в запросе жестко задано значение null вместо переменной, которая в настоящий момент имеет значение null.

Второй запрос создаст

SELECT .......
WHERE NullableInt == @someParam
WHERE @someParam is null.

Где первыйсгенерирует соответствующий IS NULL в предложении WHERE.

Если вы используете LINQ-to-SQL, вы можете записать свои запросы в Console.Out, чтобы убедиться в этом сами, и если выиспользуя EF, ToTraceString () должна показать ту же информацию (или профилировщик SQL Server)

3 голосов
/ 12 июня 2013

ТЛ; др

Если вы используете DbContext в EF6, это исправлено.

Если вы используете EF5 (или ObjectContext в EF6), вам нужно установить для ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior значение true. Для этого на DbContext используйте это:

((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;

.

Подробнее

Основной причиной этой проблемы является различие в том, как база данных сравнивает нулевые значения и как C # сравнивает нулевые значения. Поскольку вы пишете свой запрос в C #, вы хотите использовать семантику C #.

В EF5 мы ввели ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior, который позволил вам использовать семантику C # вместо семантики базы данных. По умолчанию используется значение false (чтобы существующие запросы волшебным образом не начинали возвращать разные результаты при обновлении до EF5). Но вы можете установить его в true, и оба ваших запроса будут возвращать строки.

Если вы используете DbContext в EF5, вам нужно перейти в ObjectContext, чтобы установить его:

((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;

Если вы используете EF6, то для DbContext оно уже установлено в значение true, так что вы готовы. Мы решили, что это вызывает столько путаницы, что стоит принять потенциальное влияние на существующие запросы.

2 голосов
/ 10 февраля 2011

Запросы могут быть построены следующим образом:

var q = db.tests;
if(nullableInt.HasValue)
{
   q = q.Where(x => x.NullableInt == nullableInt.Value);
}
else
{
   q = q.Where(x => x.NullableInt == null);
}
var t2 = q.ToList();
0 голосов
/ 10 февраля 2011

будет делать:

var t2 = db.tests.Where(x => x.NullableInt == nullableInt ?? null).ToList(); 

Работа

Хотя это похоже на полное безумие.

0 голосов
/ 10 февраля 2011

Существует другое решение, которое всегда будет работать, хотя и с небольшой оговоркой:

int? nullableInt = null;
var t2 = db.tests.Where(x => object.Equals(x.NullableInt, nullableInt)).ToList();

Когда значение равно нулю, вы получите правильный запрос IS NULL, однако, когда оно не равно нулю, вы получитечто-то вроде:

SELECT ...
WHERE ([t0].[NullableInt] IS NOT NULL) AND ([t0].[NullableInt] = @p0) 

Очевидно, что у него есть дополнительное условие (источник чего-то озадачивает).При этом оптимизатор запросов SQL Server должен обнаружить, что, поскольку @ p0 является ненулевым значением, первое условие является надмножеством и обрезает предложение where.

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