2016-05-10 11 views
1

Использование: Entity Framework 4.3.1, MVC 4нуль против по умолчанию установлен в нуль - дает разные результаты

записей базы данных Sample (например):

 
Id Height 
1  null 
2  2.1 

Почему этот первый отчет возвращает нулевые результаты:

decimal? scannedItemHeight = default(decimal?); 

(from st in Stocks 
where st.Height == scannedItemHeight 
select st.Id).ToList(); 

Но это заявление возвращает запись Id 1:

(from st in Stocks 
where st.Height == null 
select st.Id).ToList(); 

Если scannedItemHeight имеет значение NULL, я хочу только совместить значения, где высота тоже нулевая.

Я только хочу, чтобы вернуть первую запись, Id 1.

UPDATE Я закончил с использованием:

st.Height == scannedItemHeight || (scannedItemHeight == null && st.Height == null) 
+0

Записывать фактические операторы SQL, которые генерируются и посмотреть, если есть разница. Http: // StackOverflow.com/questions/16880687/how-can-i-log-the-generated-sql-from-dbcontext-savechanges-in-my-program –

+1

У вас на самом деле есть элементы с ненулевой высотой, которые соответствуют другим условиям? В противном случае результаты для обоих методов будут одинаковыми в этом случае (потому что метод Jon возвращает только элементы с Height is null, а мой метод - только все элементы). Очень важно понять различие между этими методами. Поскольку я undestand вам нужно сопоставить элементы с нулевой высотой, если параметр равен нулю, используйте метод Jon. – Evk

+0

@ Evk Doh! Я думаю, что вы правы, я выбрал высоту для примера и не проверял, что для других заданных параметров фильтрации (ширина, длина, калибровка), что все результаты имеют нулевую высоту, позвольте мне повторить проверку и вернуться к вам, но да, это все объяснило бы. –

ответ

3

Это потому, что в первом случае запроса к базе данных будет что-то вроде

where Height = @param1 ... 

Хотя во втором случае это было бы

where Height is null 

Первый запрос не будет возвращать никаких результатов, потому что @ param1 будет null, и никакая строка не сможет соответствовать такому условию.

Главное, что с точки зрения C# эти запросы эквивалентны, но с точки зрения sql они не являются: вы должны использовать IS NULL (или IS NOT NULL) в sql для проверки нулей.

Как исправить, зависит от того, что вы хотите сделать, когда ваш параметр равен NULL. В вашем случае: использовать ответ Джона Скита.

Если кто-то захочет игнорировать параметр, а не фильтровать его вообще (довольно обычный случай, например, когда параметр представляет собой ввод пользователя в каком-либо поле, а когда ничего не набирается там - ничего не фильтровать), тогда выполните:

where scannedItemHeight == null || st.Height == scannedItemHeight 

, который будет в SQL, как

where @param1 is null OR Height = @param1 
+0

Хм ... имеет смысл ... так как я могу передать десятичную переменную с нулевым значением и ее обрабатывать так же, как «равно null»? –

+0

@PaulZahra см. Обновление – Evk

+0

Hang on - это дает неправильные результаты, хотя, конечно ... если 'scannedItemHeight' равно null, предположительно, OP * только * хочет сопоставить значения, где' st.Height' равно null, тогда как это будет включать значения, где 'st.Height' имеет любое значение ... –

3

Я, конечно, видел некоторые странное поведение LINQ до сих пор, из-за способ, которым SQL обрабатывает значения NULL, не совпадает с тем, как C# обрабатывает значения NULL. В C# a == b имеет значение true, если a и b оба являются нулевыми, тогда как в SQL они не ... вместо этого вы должны преднамеренно проверить недействительность. Я хотел бы попробовать:

var temp = (from st in Stocks 
      where st.Height == scannedItemHeight || (scannedItemHeight == null && st.Height == null) 
      select st.Id).ToList(); 

Или строить запросы по-разному:

var filtered = scannedItemHeight == null 
    ? Stocks.Where(st => st.Height == null) 
    : Stocks.Where(st => st.Height == scannedItemHeight); 
var temp = filtered.Select(st => st.Id).ToList();