Почему IS NULL работает, а параметр SQL с DBNull.Value для DateTime не работает?

У меня есть консольное приложение С#, которое выполняет поиск в базе данных на SQL Server 2014. Оно запрашивает таблицу со столбцом DateTime с именем EffectiveDate, который допускает нули.

Если я пишу стандартный SQL-запрос, который использует «ГДЕ EffectiveDate IS NULL», результаты возвращаются правильно. Если я изменю предложение WHERE, чтобы принять параметр, и установлю для этого параметра значение DBNull.Value, результат будет нулевым.

Пример 1 Использование IS NULL -> resultObj имеет соответствующее значение:

    public void RetrieveFileType()
    {
        string sSQL = "SELECT [FileType]  " +
                      "FROM DTCC_APP_ProcessControl " +
                      "WHERE [EffectiveDate] IS NULL ";

        using (SqlConnection oConn = GetNewConnection())
        {
            using (SqlCommand cmd = new SqlCommand(sSQL, oConn))
            {
                object resultObj = cmd.ExecuteScalar();
            }
        }
    }

Пример 2. Использование DBNull.Value -> resultObj = null:

    public void RetrieveFileType()
    {
        string sSQL = "SELECT [FileType]  " +
                      "FROM DTCC_APP_ProcessControl " +
                      "WHERE [EffectiveDate] = @EffectiveDate";

        using (SqlConnection oConn = GetNewConnection())
        {
            using (SqlCommand cmd = new SqlCommand(sSQL, oConn))
            {
                cmd.Parameters.AddWithValue("@EffectiveDate", DBNull.Value);

                object resultObj = cmd.ExecuteScalar();
            }
        }
    }

Я также пробовал:

cmd.Parameters.Add("@EffectiveDate", SqlDbType.DateTime).Value = DBNull.Value;

и

cmd.Parameters.AddWithValue("@EffectiveDate", SqlDateTime.Null);

Единственный раз, когда я получаю результат, это если я использую IS NULL. Это упрощенный пример, я буду дополнительно устанавливать значение или Null для @EffectiveDate.

Я прочитал другую информацию в Интернете, и кажется, что все, что мне нужно, это столбец базы данных, допускающий значение NULL, и использование DBNull.Value для параметра, и он должен работать. Что мне не хватает?


person sldorman    schedule 03.10.2018    source источник
comment
Похоже, вы используете необработанный ADO.NET. Рассматривали ли вы возможность перехода на что-то, что упрощает работу с ADO.NET, например Dapper?   -  person mason    schedule 03.10.2018
comment
Вы не можете проверить ноль с оператором равенства   -  person Milad Aghamohammadi    schedule 03.10.2018


Ответы (2)


Проблема не в параметризации, а в том, что параметр может иметь значение NULL. Подобно тому, что сказал Стив ранее, вы не можете напрямую сравнивать NULL с NULL, иначе он ничего не вернет (в соответствии со стандартом SQL он всегда оценивается как false).

Прямое сравнение в вашем примере 2 работает хорошо, когда параметр гарантированно никогда не будет NULL, пример 1 в порядке, если он всегда будет NULL. Однако, если есть вероятность того, что это NULL или нет в соответствии с каким-то внешним условием, мы должны учитывать это и в SQL-запросе. Что-то вроде этого будет делать:

SELECT [FileType]
FROM DTCC_APP_ProcessControl
WHERE [EffectiveDate] = @EffectiveDate OR @EffectiveDate IS NULL

Это подходит для обеих ситуаций, однако обратите внимание, что это выражение не допускает SARG и не будет использовать индекс для столбцов EffectiveDate, если он есть.

Альтернативный подход заключается в том, что в соответствии с окончательным значением параметра клиент выбирает отправку того или иного запроса, динамически выбирая между примером 1 или 2. Это, вероятно, приведет к лучшей производительности и использованию индекса.

person Alejandro    schedule 03.10.2018
comment
Оказывается, все примеры, которые я видел, где параметры использовались с DBNull.Value, были инструкциями Insert. Я не замечал этого раньше. Я думал, что DBNull.Value приведет к IS NULL в конечном запросе. Спасибо за объяснение. - person sldorman; 03.10.2018
comment
@sldorman С INSERT такой проблемы нет, потому что они не используются для сравнения, в этом корень проблемы, сравнивая столбец с NULL, даже не имеет значения, является ли это параметром или нет. Все, что делает параметр, это отделяет данные от самого запроса, но он не учитывает ничего другого, IS NULL зависит от вас, если вы хотите (и вы действительно хотите его здесь). - person Alejandro; 03.10.2018

Потому что NULL в БД отличается от С#.

NULL = NULL возвращает false в Sql. Вы должны использовать IS NULL для сравнения

person Steve    schedule 03.10.2018