Ответ 1
Запросы могут быть построены таким образом:
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();
У меня есть таблица под названием "test", которая имеет только 1 столбец "NullableInt" (тип NULL 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"
Любая помощь будет принята с благодарностью!
Запросы могут быть построены таким образом:
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();
Yep - это ошибка в LINQ-to-SQL/Entity Framework. IS NULL
запросы будут генерироваться только в том случае, если вы задаете нулевой запрос в запросе вместо переменной, которая в настоящее время является нулевой.
Второй запрос будет генерировать
SELECT .......
WHERE NullableInt == @someParam
WHERE @someParam is null.
Если первый генерирует соответствующий IS NULL
в предложении WHERE
.
Если вы используете LINQ-to-SQL, вы можете записывать свои запросы в Console.Out, чтобы убедиться сами, и если вы используете EF, то ToTraceString() должен показывать вам ту же информацию (или SQL Server профилировщик)
TL;DR
Если вы используете DbContext в EF6, это исправлено.
Если вы используете EF5 (или ObjectContext в EF6), вам необходимо установить ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior в true. Для этого в DbContext используйте это:
((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;
.
Подробнее
Коренной причиной этой проблемы является различие в том, как база данных сравнивает нулевые значения и как С# сравнивает нулевые значения. Поскольку вы пишете свой запрос в С#, вы хотите использовать семантику С#.
В EF5 мы ввели ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior, который позволил вам выбрать семантику С# вместо семантики базы данных. Значение по умолчанию - false (так что существующие запросы не волшебным образом начинают возвращать разные результаты при обновлении до EF5). Но вы можете установить его в true, и ваши запросы возвратят строки.
Если вы используете DbContext в EF5, вам нужно опуститься до ObjectContext, чтобы установить его:
((IObjectContextAdapter)db).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;
Если вы используете EF6, тогда он уже установлен на true в DbContext, поэтому вам хорошо идти. Мы решили, что это вызывает столько путаницы, что стоило потенциально повлиять на существующие запросы.
Существует еще одно решение, которое всегда будет работать, хотя и с небольшим предостережением:
int? nullableInt = null;
var t2 = db.tests.Where(x => object.Equals(x.NullableInt, nullableInt)).ToList();
Когда значение равно null, вы получите правильный IS NULL
запрос, однако, когда его значение не равно null, вы получите что-то вроде:
SELECT ...
WHERE ([t0].[NullableInt] IS NOT NULL) AND ([t0].[NullableInt] = @p0)
Очевидно, что у него есть условие extra (источник которого вызывает недоумение). При этом оптимизатор запросов SQL Server должен обнаружить это, поскольку @p0 является ненулевым значением, первое условие является надмножеством и сократит предложение where.
Делал:
var t2 = db.tests.Where(x => x.NullableInt == nullableInt ?? null).ToList();
Работа?
Похоже, это безумие.