SqlParameter (строка, объект) не может обрабатывать постоянное значение

У меня есть функция, в которой я отправляю два запроса в базу данных SQL Server; однако по второму запросу я получаю SqlException, а параметр @mpe отсутствует. Если я попытаюсь установить постоянное значение 0 в конструкторе SqlParameter.

    protected static string GetX(int mpe, string xsection, string xkey)
    {
        var xSetup = App.Current.Db.GetType<Data.CachedTypes.XSetup>(
            "where mpehotel=@mpe and xsection=@xsection and xkey=@xkey",
            new System.Data.SqlClient.SqlParameter("@mpe", mpe),
            new System.Data.SqlClient.SqlParameter("@xsection", xsection),
            new System.Data.SqlClient.SqlParameter("@xkey", xkey));

        if (mpe > 0 && xSetup == null)
        {
            // Fallback mechanism. Always tries to get the default for all MPEs.
            xSetup = App.Current.Db.GetType<Data.CachedTypes.XSetup>(
                "where mpehotel=@mpe and xsection=@xsection and xkey=@xkey",
                new System.Data.SqlClient.SqlParameter("@mpe", 0), <-- THIS FAILES!!
                new System.Data.SqlClient.SqlParameter("@xsection", xsection),
                new System.Data.SqlClient.SqlParameter("@xkey", xkey));

Однако если я извлеку постоянное значение 0 в локальное значение int xmpe = 0 и передам его конструктору, SQL-запрос выполнится, как и ожидалось, и будет получен результат. Может кто-нибудь объяснить, почему это происходит?


person Jens Marchewka    schedule 10.11.2017    source источник


Ответы (1)


Это потому, что когда вы делаете это:

new System.Data.SqlClient.SqlParameter("@mpe", 0)

Используется следующий конструктор:

public SqlParameter(string parameterName, SqlDbType dbType)

Что эквивалентно:

new System.Data.SqlClient.SqlParameter("@mpe", SqlDbType.BigInt);

Это связано с тем, что 0 неявно преобразуется в любой тип перечисления, поэтому эта перегрузка предпочтительнее этой:

public SqlParameter(string parameterName, object value)

Однако, когда вы делаете

int someInt = 0; // or anything else
new System.Data.SqlClient.SqlParameter("@mpe", someInt)

Произвольное целое не может быть неявно преобразовано в перечисление (только константа 0), поэтому выбрана правильная перегрузка (с object value). Тот факт, что произвольный int также может быть равен 0, не имеет значения, потому что разрешение перегрузки выполняется во время компиляции. Однако, если вы сделаете это:

const int mpe = 0;
new System.Data.SqlClient.SqlParameter("@mpe", mpe);

Затем снова выбирается неверный конструктор, потому что известно, что mpe равно 0 во время компиляции. Если вы сделаете это:

const int mpe = 1;
new System.Data.SqlClient.SqlParameter("@mpe", mpe);

Затем снова выбирается object value по вышеуказанным причинам.

Чтобы все время принудительно корректировать перегрузку, приведите 0 к объекту:

new System.Data.SqlClient.SqlParameter("@mpe", (object) 0);
person Evk    schedule 10.11.2017
comment
Вот и все, new SqlParameter("name", (object)0) работает с ожидаемым поведением. - person Jens Marchewka; 10.11.2017