VB.Net Linq to Entities Null Сравнение — «ничего» или «= ничего»?

У нас есть несколько проектов в VB.Net, использующих .Net Framework 4 и Linq to Entities для многих наших SQL-запросов. Переход на EF — это новое изменение для нас (используем его около 4-6 месяцев), и оно поддерживается высшим руководством, потому что мы можем кодировать намного быстрее. Мы по-прежнему используем много хранимых процессов, но даже выполняем их через Linq to Entities.

Я надеюсь прояснить некоторую путаницу, и я не могу найти прямой ответ, который имеет смысл. У нас есть несколько запросов, в которых нам нужны записи, в которых определенное поле имеет значение NULL. Это простые запросы на выборку, без агрегатов или левых объединений и т. д. Microsoft рекомендует, чтобы запрос выглядел примерно так: Ссылка MSDN:

dim query = from a in MyContext.MyTables
Where a.MyField = Nothing
Select a

У меня есть несколько проектов, где я делаю именно это, и это прекрасно работает, никаких предупреждений в IDE. Недавно другим разработчиком был создан новый проект, и когда он выполнил проверку нуля, как описано выше, мы все получили это предупреждение в среде IDE:

Предупреждение 1. Это выражение всегда будет оцениваться как Nothing (из-за распространения null от оператора равенства). Чтобы проверить, является ли значение нулевым, рассмотрите возможность использования «Нет ничего».

При сравнении проектов для каждого из них включены опции «явно» и «строго». Если мы проигнорируем предупреждение, мы получим точный набор записей, который мы ищем, когда приложение запускается. Предупреждение исчезнет, ​​если я изменю знак = на IS. Но почему это предупреждение появилось в одном проекте, а не в другом? Это сбивает с толку, когда даже в MSDN есть примеры использования оператора равенства.


person Community    schedule 10.07.2012    source источник
comment
VB.NET LINQ также имеет ключевое слово Equals. У меня нет способа проверить это, но, может быть, попробовать вместо этого? Where a.MyField Equals Nothing   -  person Cᴏʀʏ    schedule 10.07.2012
comment
@Cory: это контекстное ключевое слово, которое используется только в предложениях Join (AFAIK). Я не думаю, что вы можете использовать его где-нибудь еще.   -  person Jeff Mercado    schedule 10.07.2012


Ответы (3)


Я полагаю, что вы видите здесь то, что MyField является типом Nullable(Of T). Скорее всего примитив Integer, Single и т.д...

Причина, по которой вы видите это предупреждение, заключается в том, что компилятор переводит обычный оператор равенства для примитивного типа в версию Nullable(Of T). По сути, он выполняет следующее

Dim myField As Integer? = a.MyField
Dim other As Integer? = Nothing
If myField = other Then
 ...
End If

Однако проблема в том, что когда Integer? имеет значение Nothing, оно не будет сравниваться ни с чем. Следовательно, приведенное выше предложение Where всегда будет возвращать False. Компилятор пытается предупредить вас об этом проблемном углу Nullable(Of T) и подтолкнуть вас к проверке Is Nothing, которая определит, имеет ли a.MyField ненулевое значение.

В этой статье блога есть очень подробное объяснение того, почему генерируется это предупреждение, и всех механизмов, стоящих за ним. Статья написана для C#, но основная идея применима и к VB.Net.

person JaredPar    schedule 10.07.2012
comment
Итак, если я правильно понимаю, знак равенства работал в одном запросе, потому что поле не допускало значения NULL, но было проблемой в другом запросе, поскольку оно допускало значение NULL, поэтому требовался другой синтаксис. - person ; 12.07.2012
comment
@КрисДжонс правильно. Обычно вы можете использовать = со значением, допускающим значение NULL. Сравнение с Nothing всегда будет возвращать False, поэтому компилятор выдает предупреждение об этом. - person JaredPar; 12.07.2012
comment
Поиграв с этим еще немного, я могу сделать = Nothing для строковых полей, которые могут быть нулевыми в базе данных, но не для других типов данных и могут либо использовать Is Nothing, либо член HasValue, о котором упоминал Афшин. Спасибо, что пролили свет на это. - person ; 12.07.2012

Сгенерированный столбец должен быть Nullable(Of T)

Таким образом, вы можете проверить, имеет ли это поле значение или нет:

dim query = from a in MyContext.MyTables
Where Not a.MyField.HasValue
Select a
person Afshin Gh    schedule 10.07.2012
comment
Я попробовал это для нескольких типов данных, и это не сработало со строковыми значениями. Я смог использовать элемент HasValue для целочисленных, датированных и логических типов данных, допускающих значение NULL. - person ; 12.07.2012

По крайней мере, в LINQ для объектов вы можете использовать это вместо этого:

Nullable(Of Integer).Equals(a, b)

Это прекрасно работает с обоими, либо с любым из двух значений, равным Nothing, либо ни с одним из них.

person Ronny Heuschkel    schedule 11.10.2017