Присвоить ноль для SqlParameter

189

Следующий код выдает ошибку - «Нет неявного преобразования из DBnull в int».

SqlParameter[] parameters = new SqlParameter[1];    
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex;
parameters[0] = planIndexParameter;
относительность
источник
4
Вам нужно привести AgeItem.AgeIndex к объекту, я думаю ... stackoverflow.com/questions/202271/… (кстати, почему ==в конце 3-й строки?)
Грег,

Ответы:

341

Проблема заключается в том, что ?:оператор не может определить тип возвращаемого intзначения, поскольку вы либо возвращаете значение, либо значение типа DBNull, которые несовместимы.

Конечно, вы можете привести экземпляр AgeIndex к типу, objectкоторый удовлетворял бы ?:требованию.

Вы можете использовать ??оператор слияния нуля следующим образом

SqlParameter[] parameters = new SqlParameter[1];     
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
planIndexParameter.Value = (object)AgeItem.AgeIndex ?? DBNull.Value;
parameters[0] = planIndexParameter; 

Вот цитата из документации MSDN для ?:оператора, которая объясняет проблему

Либо тип first_expression и second_expression должен быть одинаковым, либо должно существовать неявное преобразование из одного типа в другой.

Крис Тейлор
источник
Почему не возникает исключение при попытке привести null к объекту? Я думаю, что это должно бытьAgeItem.AgeIndex as object
Нильс Бринч
@Niels Brinch, не было бы исключения, потому что null - это объект, и если вы не пытаетесь разыменовать его, это совершенно законно. Однако в этом примере это не нулевое приведение к объекту, это DBNull.Value, который на самом деле является типом значения. ?? Оператор говорит: «Если AgetItem.AgeIndex равен нулю, тогда возвращать DBNull.Value, в противном случае повторно вызывать AgeItem.AgeIndex», тогда ответ приводится к объекту. Смотрите ноль оператор объединения для получения более подробной информации. msdn.microsoft.com/en-us/library/ms173224.aspx
Крис Тейлор
3
Технически, ваше решение с помощью нуль-сливающихся оператора ??является то же решением , как если бы вы использовали регулярные тройной ?:- вам все равно нужно гипс AgeItem.AgeIndexк объекту: planIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;.
newfurniturey
Если бы вы использовали обычную троичную комбинацию ?:для сравнения конкретных типов, тогда приведение всего выражения не сработает. Вы должны разыграть не-dbnull параметр следующим образом:someID == 0 ? DBNull.Value : (object)someID
ингридиент_15939
Это верно, но если вам нужно использовать нулевое значение в качестве входного параметра функции, в результате которой используется SqlParameter, и если оно нулевое, у вас есть ошибка, этот способ не работает, и вы должны использовать простой способ If-Else. например: sample.Text.Trim ()! = ""? func (sample.Text): DBNull.Value; не будет работать как? а ??
QMaster
105

Принятый ответ предполагает использование броска. Однако большинство типов SQL имеют специальное поле Null, которое можно использовать, чтобы избежать этого приведения.

Например, SqlInt32.Null«Представляет DBNull, который может быть назначен этому экземпляру класса SqlInt32».

int? example = null;
object exampleCast = (object) example ?? DBNull.Value;
object exampleNoCast = example ?? SqlInt32.Null;
Брайан
источник
2
Предложение выглядело многообещающе, поэтому я попробовал «System.Data.SqlTypes.SqlString.Null», но оно не работает. Он помещает в поле фактическую строку «Null» ('N', 'u', 'l', 'l'), оставляя пустым значение true (null). Тем не менее, старый 2010 "принятый ответ", который использует приведение с (объект) ?? DBNull.Value работает правильно. (Поставщиком ADO.NET, который я использовал, был SQLite, но я не уверен, имеет ли это значение.) Я предлагаю, чтобы другие тщательно протестировали совет Брайана, чтобы убедиться, что нулевое поведение работает должным образом.
JasDev
6
@JasDev: Я смутно припоминаю, как описывал этот трюк в комментарии высокопоставленному пользователю (думаю, Марк Грэвелл), и мне говорили, что он работает только на Microsoft SQL Server.
Брайан
@JasDev, провайдер будет тем отличием, что это работает в SQL Server, как указывает Мозг.
Lankymart
Этот ответ заменяет только явное приведение к объекту неявным. One. В примере кода exampleNoCastобъявлен объект, поэтому приведение к объекту все еще происходит. Если, как и в коде OP, значение присваивается непосредственно SqlParameter.Value, который также имеет тип объекта, тогда вы все равно получите приведение.
Скотт
31

Вам необходимо передать DBNull.Valueкак пустой параметр в SQLCommand, если в хранимой процедуре не указано значение по умолчанию (если вы используете хранимую процедуру). Наилучший подход - назначить DBNull.Valueлюбой пропущенный параметр перед выполнением запроса, и следующий foreach сделает эту работу.

foreach (SqlParameter parameter in sqlCmd.Parameters)
{
    if (parameter.Value == null)
    {
        parameter.Value = DBNull.Value;
    }
}

В противном случае измените эту строку:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex;

Следующим образом:

if (AgeItem.AgeIndex== null)
    planIndexParameter.Value = DBNull.Value;
else
    planIndexParameter.Value = AgeItem.AgeIndex;

Потому что вы не можете использовать разные типы значений в условных выражениях, так как DBNull и int отличаются друг от друга. Надеюсь, это поможет.

ShahidAzim
источник
Этот ответ действительно хорош, потому что он дает примеры во всех отношениях. Мне нравится первый подход, я обычно использую EF, но в этом требовании не могу этого сделать, и это экономит мне много времени. Спасибо!
Леандро
23

С одной строкой кода попробуйте это:

var piParameter = new SqlParameter("@AgeIndex", AgeItem.AgeIndex ?? (object)DBNull.Value);
Адриан
источник
5

Попробуй это:

SqlParameter[] parameters = new SqlParameter[1];    
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);

planIndexParameter.IsNullable = true; // Add this line

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex== ;
parameters[0] = planIndexParameter;
decyclone
источник
5

Если вы используете условный (троичный) оператор, компилятору требуется неявное преобразование между обоими типами, в противном случае вы получите исключение.

Таким образом, вы можете исправить это, приведя один из обоих к System.Object:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : (object) AgeItem.AgeIndex;

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

public static object GetDBNullOrValue<T>(this T val)
{
    bool isDbNull = true;
    Type t = typeof(T);

    if (Nullable.GetUnderlyingType(t) != null)
        isDbNull = EqualityComparer<T>.Default.Equals(default(T), val);
    else if (t.IsValueType)
        isDbNull = false;
    else
        isDbNull = val == null;

    return isDbNull ? DBNull.Value : (object) val;
}

Тогда вы можете использовать этот краткий код:

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue();
Тим Шмельтер
источник
1

На мой взгляд, лучше сделать это с помощью свойства Parameters класса SqlCommand :

public static void AddCommandParameter(SqlCommand myCommand)
{
    myCommand.Parameters.AddWithValue(
        "@AgeIndex",
        (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex);
}

источник
Но если значение равно DBNull.Value, ADO.NET может быть довольно сложно угадать, какой это может быть SqlDbType ........ это удобно - но немного опасно ...
marc_s
1

Подумайте об использовании доступной структуры Nullable (T). Это позволит вам устанавливать значения только в том случае, если они у вас есть, и ваши объекты SQL Command будут распознавать обнуляемое значение и обрабатываться соответствующим образом без каких-либо хлопот с вашей стороны.

Канвар Сингх
источник
1
if (_id_categoria_padre > 0)
{
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre;
}
else
{
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value;
}
Анил Кумар
источник
0

Попробуй это:

if (AgeItem.AgeIndex != null)
{
   SqlParameter[] parameters = new SqlParameter[1];
   SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
   planIndexParameter.Value = AgeItem.AgeIndex;
   parameters[0] = planIndexParameter;
}

Другими словами, если параметр имеет значение null, просто не отправляйте его в свой хранимый процесс (при условии, конечно, что хранимый процесс принимает нулевые параметры, что подразумевается в вашем вопросе).

Flipster
источник
Но теперь вы просто опускаете параметр - я очень сомневаюсь, что хранимая процедура будет рада этому ... скорее всего, вызов не удастся, сообщив, что "значение для параметра @AgeIndex не предоставлено, что ожидалось" .... .
marc_s
Вот это да. Суровая. Просто запишите сохраненный процесс в значение по умолчанию, если параметр не передан (@AgeIndex int = 0). Бывает все время. Клиент может либо принять значение по умолчанию, либо переопределить его, передав параметр. Почему отрицательный голос?
Flipster
0

попробуйте что-то вроде этого:

if (_id_categoria_padre > 0)
{
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre;
}
else
{
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value;
}
user2574441
источник
0
int? nullableValue = null;
object nullableValueDB
{
   get{
       if(nullableValue==null)
          return DBNull.Value;
       else
          return (int)nullableValue;
   }
}

Я так решаю.

Синан Дирек
источник
0
if (AgeItem.AgeIndex== null)  
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = DBNull);  
else  
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = AgeItem.AgeIndex);
Анил Кумар
источник
0

Это то, что я просто делаю ...

        var PhoneParam = new SqlParameter("@Phone", DBNull.Value);
        if (user.User_Info_Phone != null)
        {
            PhoneParam.SqlValue = user.User_Info_Phone;
        }

        return this.Database.SqlQuery<CustLogonDM>("UpdateUserInfo @UserName, @NameLast, @NameMiddle, @NameFirst, @Address, @City, @State, @PostalCode, @Phone",
            UserNameParam, NameLastParam, NameMiddleParam, NameFirstParam, AddressParam, CityParam, StateParam, PostalParam, PhoneParam).Single();
Том Мак
источник
0
            dynamic psd = DBNull.Value;

            if (schedule.pushScheduleDate > DateTime.MinValue)
            {
                psd = schedule.pushScheduleDate;
            }


            sql.DBController.RunGeneralStoredProcedureNonQuery("SchedulePush",
                     new string[] { "@PushScheduleDate"},
                     new object[] { psd }, 10, "PushCenter");
papapa
источник
0

Простой метод расширения для этого будет:

    public static void AddParameter(this SqlCommand sqlCommand, string parameterName, 
        SqlDbType sqlDbType, object item)
    {
        sqlCommand.Parameters.Add(parameterName, sqlDbType).Value = item ?? DBNull.Value;
    }
отметка
источник
0

Я использую простой метод с нулевой проверкой.

    public SqlParameter GetNullableParameter(string parameterName, object value)
    {
        if (value != null)
        {
            return new SqlParameter(parameterName, value);
        }
        else
        {
            return new SqlParameter(parameterName, DBNull.Value);
        }
    }
Чжи Ань
источник
1
Это условная логика в обратном направлении? Должен ли DBNull.Value быть первым?
Марк Шультхайс
Конечно, есть. Исправлена. Спасибо.
Чжи Ан
0

Мой код, работающий в реальном проекте. Посмотрите на троичный оператор, прежде чем сделать sqlparameter для меня лучшим способом, без проблем:

    public bool Key_AddExisting
    (
          string clave
        , int? idHito_FileServer
        , int? idTipoDocumental_Almacen
        , string tipoExp_CHJ
        , int idTipoExp_Verti2
        , int idMov_Verti2
    )
    {
        List<SqlParameter> pars = new List<SqlParameter>()
        {
              new SqlParameter { ParameterName = "@Clave", Value = clave }
    LOOK -> , idHito_FileServer == null ? new SqlParameter { ParameterName = "@IdHito_FileServer", Value = DBNull.Value } : new SqlParameter { ParameterName = "@IdHito_FileServer", Value = idHito_FileServer }
    LOOK -> , idTipoDocumental_Almacen == null ? new SqlParameter { ParameterName = "@IdTipoDocumental_Almacen", Value = DBNull.Value } : new SqlParameter { ParameterName = "@IdTipoDocumental_Almacen", Value = idTipoDocumental_Almacen }
            , new SqlParameter { ParameterName = "@TipoExp_CHJ", Value = tipoExp_CHJ }
            , new SqlParameter { ParameterName = "@IdTipoExp_Verti2", Value = idTipoExp_Verti2 }
            , new SqlParameter { ParameterName = "@IdMov_Verti2", Value = idMov_Verti2 }
        };

        string sql = "INSERT INTO [dbo].[Enlaces_ClavesCHJ_MovimientosVerti2] " +
            "( " +
            "  [Clave] " +
            ", [IdHito_FileServer] " +
            ", [IdTipoDocumental_Almacen] " +
            ", [TipoExp_CHJ] " +
            ", [IdTipoExp_Verti2] " +
            ", [IdMov_Verti2] " +
            ") " +
            "VALUES" +
            "( " +
            "  @Clave" +
            ", @IdHito_FileServer" +
            ", @IdTipoDocumental_Almacen" +
            ", @TipoExp_CHJ" +
            ", @IdTipoExp_Verti2" +
            ", @IdMov_Verti2" +
            ")";

        return DbBasic.ExecNonQuery(ref this.conn, sql, pars);
    }
Анхель Ибаньес
источник