Почему конструктор имени / значения SqlParameter обрабатывает 0 как ноль?

Я обнаружил странную проблему в фрагменте кода, когда специальный SQL-запрос не выдавал ожидаемого результата, даже если его параметры соответствовали записям в источнике данных. Я решил ввести следующее тестовое выражение в ближайшее окно:

new SqlParameter("Test", 0).Value

Это дало результат null, который оставляет меня почесывая голову. Кажется, что SqlParameter Конструктор рассматривает нули как нули. Следующий код дает правильный результат:

SqlParameter testParam = new SqlParameter();
testParam.ParameterName = "Test";
testParam.Value = 0;
// subsequent inspection shows that the Value property is still 0

Кто-нибудь может объяснить это поведение? Это как-то намеренно? Если это так, это потенциально довольно опасно...

2 ответа

Решение

Как указано в документации для этого конструктора:

При указании объекта в параметре значения SqlDbType выводится из типа объекта Microsoft .NET Framework.

Будьте осторожны при использовании этой перегрузки конструктора SqlParameter для указания целочисленных значений параметров. Поскольку эта перегрузка принимает значение типа Object, необходимо преобразовать интегральное значение в тип Object, когда значение равно нулю, как показано в следующем примере C#.

Parameter = new SqlParameter("@pname", (object)0);

Если вы не выполняете это преобразование, компилятор предполагает, что вы пытаетесь вызвать перегрузку конструктора SqlParameter (string, SqlDbType).

Вы просто вызывали конструктор, отличный от вашего случая.

Причина этого заключается в том, что C# позволяет неявное преобразование из целочисленного литерала 0 перечислять типы (которые являются просто целочисленными типами внизу), и это неявное преобразование вызывает (string, SqlDbType) конструктор лучше подходит для разрешения перегрузки, чем преобразование в бокс, необходимое для преобразования int в object для (string, object) конструктор.

Это никогда не будет проблемой, когда вы передадите int переменная, даже если значение этой переменной 0 (потому что это не нулевой литерал), или любое другое выражение, которое имеет тип int, Это также не произойдет, если вы явно разыгрываете int в object как видно выше, потому что тогда существует только одна соответствующая перегрузка.

Рекомендуется использовать типизированные данные при передаче / добавлении параметров.

Ниже вы можете выполнить задачу, как показано ниже:

Для строковых / типизированных данных:

SqlParameter pVarchar = new SqlParameter
                    {
                        ParameterName = "Test",
                        SqlDbType = System.Data.SqlDbType.VarChar,
                        Value = string.Empty,
                    };

Для типизированных данных int:

SqlParameter pInt = new SqlParameter
                    {
                        ParameterName = "Test",
                        SqlDbType = System.Data.SqlDbType.Int,
                        Value = 0,
                    };

Вы можете изменить значение SqlDbType согласно вашим используемым данным.

Другие вопросы по тегам