SqlParameter öğesine null atama


189

Aşağıdaki kod bir hata veriyor - "DBnull'dan int'e örtük dönüştürme yok."

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
Sanırım itiraz etmek için AgeItem.AgeIndex döküm gerekir ... stackoverflow.com/questions/202271/… (btw, neden ==3. satırın sonunda?)
Greg

Yanıtlar:


341

Sorun, ?:işleç, uyumlu olmayan bir intdeğer veya bir DBNull türü değeri döndürdüğünüz için dönüş türünü belirleyememesidir .

Elbette AgeIndex örneğini object, ?:gereksinimi karşılayacak bir tür olarak yayınlayabilirsiniz .

??Null birleştirme operatörünü aşağıdaki gibi kullanabilirsiniz

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

İşte sorunu açıklayan işleç için MSDN belgelerinden bir alıntı?:

First_expression ve second_expression türlerinin aynı olması veya bir türden diğerine örtük bir dönüşüm olması gerekir.


Nesneye null atmaya çalışırken neden bir istisna yok? Olması gerektiğini düşünürdümAgeItem.AgeIndex as object
Niels Brinch

@Niels Brinch, bir istisna olmaz çünkü null bir nesnedir ve başvuruyu denemediğiniz sürece, tamamen yasaldır. Ancak, bu örnekte nesneye atanan boş değer değil, aslında bir değer türü olan DBNull.Value değeridir. ?? işleci 'AgetItem.AgeIndex boşsa DBNull.Value döndürür aksi takdirde AgeItem.AgeIndex döndürür' diyor yanıt nesneye verilir. Daha fazla ayrıntı için null birleştirme operatörüne bakın. msdn.microsoft.com/en-us/library/ms173224.aspx
Chris Taylor

3
Teknik olarak, boş-kaynaştırma operatörü kullanarak çözüm ??düzenli ve üçlü kullanmak sanki aynı çözümdür ?:- hala döküm gereken AgeItem.AgeIndexbir nesneye: planIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;.
newfurniturey

Türe ?:özgü bir karşılaştırma yapmak için normal üçlü kullanacaksanız , tüm ifadeyi yayınlamak işe yaramaz. Sen gibi pek olmayan DBNull parametreyi döküm zorunda:someID == 0 ? DBNull.Value : (object)someID
ingredient_15939

Bu doğrudur, ancak sonuç olarak SqlParameter tüketen bir işlev giriş parametresi olarak null-güçlü değeri kullanmanız gerekiyorsa ve null ise bu şekilde hata alırsınız ve sadece basit If-Else yolunu kullanmalısınız. örneğin: sample.Text.Trim ()! = ""? işlev (sample.Text): DBNull.Value; olarak çalışmaz?: ve ??
QMaster

105

Kabul edilen cevap , oyuncu kadrosunun kullanılmasını önermektedir. Ancak, SQL türlerinin çoğunda bu dökümden kaçınmak için kullanılabilecek özel bir Boş alan vardır.

Örneğin, SqlInt32.Null"SqlInt32 sınıfının bu örneğine atanabilen bir DBNull öğesini temsil eder."

int? example = null;
object exampleCast = (object) example ?? DBNull.Value;
object exampleNoCast = example ?? SqlInt32.Null;

2
Öneri umut verici görünüyordu bu yüzden "System.Data.SqlTypes.SqlString.Null" denedim ama çalışmıyor. Gerçek "Null" ('N', 'u', 'l', 'l') dizesini bunun yerine true (null) ile boş bırakır. Ancak, (nesne) ile döküm kullanan eski 2010 "kabul edilen cevap" ?? DBNull.Value düzgün çalışıyor. (Kullandığım ADO.NET sağlayıcısı SQLite idi, ancak bunun bir fark yaratıp yaratmadığından emin değilim.) Diğerlerinin null davranışın beklendiği gibi çalıştığından emin olmak için Brian'ın ipucunu dikkatlice test etmelerini öneriyorum.
JasDev

6
@JasDev: Bu hileyi yüksek rep kullanıcısına yaptığı bir yorumda açıklamayı hatırlıyorum (sanırım Marc Gravell) ve sadece Microsoft SQL Server'da çalıştığı söyleniyor.
Brian

@JasDev sağlayıcı bu nokta beyin noktası olarak SQL Server'da çalışır farkı olacaktır.
Lankymart

Bu yanıt yalnızca nesneye yönelik açık bir dökümün yerine bir implicit.one ekler. Örnek kodda, exampleNoCastnesne olarak bildirilir, bu nedenle nesneye cast işlemi yine gerçekleşir. OP kodunda olduğu gibi, değer doğrudan tür nesnesi olan SqlParameter.Value öğesine atanırsa, yine de almayı alırsınız.
Scott

31

DBNull.ValueSaklı yordamda varsayılan bir değer belirtilmemişse (saklı yordam kullanıyorsanız) SQLCommand içinde null parametresi olarak geçirmeniz gerekir . En iyi yaklaşım, DBNull.Valuesorgu yürütülmeden önce herhangi bir eksik parametre atamaktır ve her foreach işini yapar.

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

Aksi takdirde bu satırı değiştirin:

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

Aşağıdaki gibi:

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

Koşullu deyimde farklı türde değerler kullanamayacağınız için, DBNull ve int birbirinden farklıdır. Umarım bu yardımcı olur.


Bu cevap gerçekten güzel çünkü mümkün olan her şekilde örnek alıyor. İlk yaklaşımı seviyorum, genellikle EF kullanıyorum ama bu şartta bunu yapamadım ve bu bana çok zaman kazandırıyor. Teşekkürler!
Leandro

23

Bir kod satırı ile şunu deneyin:

var piParameter = new SqlParameter("@AgeIndex", AgeItem.AgeIndex ?? (object)DBNull.Value);

5

Bunu dene:

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;

5

Koşullu (üçlü) operatörünü kullanırsanız, derleyicinin her iki tür arasında örtük bir dönüşüme ihtiyacı vardır, aksi takdirde bir istisna elde edersiniz.

Böylece her ikisinden birini kullanarak şunları düzeltebilirsiniz System.Object:

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

Ancak sonuç gerçekten hoş olmadığından ve her zaman bu yayınlamayı hatırlamanız gerektiğinden, bunun yerine böyle bir uzantı yöntemi kullanabilirsiniz:

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;
}

Sonra bu kısa kodu kullanabilirsiniz:

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue();

1

Bence en iyi yolu bunu SqlCommand sınıfının Parameters özelliği ile yapmaktır :

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

Ama değer ise DBNull.Value, ADO.NET ne olabilir SqlDbType olabilir tahmin zor bir zaman olabilir ........ bu uygun - ama biraz tehlikeli ....
marc_s

1

Kullanılabilir Nullable (T) yapısını kullanmayı düşünün. Yalnızca değerleriniz varsa değerleri ayarlamanıza izin verir ve SQL Komut nesneleriniz boş değer değerini tanır ve sonunda sorunsuz bir şekilde işlem yapar.


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

Bunu dene:

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

Başka bir deyişle, parametre null ise, sadece kayıtlı proc'unuza göndermeyin (elbette, saklanan proc'un sorunuzda örtük olan null parametreleri kabul ettiğini varsayarsak).


Ama şimdi, sadece bir parametreyi atlıyorsunuz - saklı yordam bu konuda mutlu olacağından şüpheliyim .... büyük olasılıkla, çağrı beklenen "@AgeIndex sağlanan parametre için hiçbir değer" belirten başarısız olur. .
marc_s

Vay. Bana ne. Parametre iletilmezse, saklanan proc değerini bir değere varsayılan olarak yazmanız yeterlidir (@AgeIndex int = 0). Her zaman olur. İstemci varsayılanı kabul edebilir veya parametreyi ileterek geçersiz kılabilir. Neden inişli çıkışlı?
Flipster

0

böyle bir şey deneyin:

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
int? nullableValue = null;
object nullableValueDB
{
   get{
       if(nullableValue==null)
          return DBNull.Value;
       else
          return (int)nullableValue;
   }
}

Ben böyle çözüyorum.


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

Ben sadece bunu yapıyorum ...

        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");

0

Bunun için basit bir uzantı yöntemi:

    public static void AddParameter(this SqlCommand sqlCommand, string parameterName, 
        SqlDbType sqlDbType, object item)
    {
        sqlCommand.Parameters.Add(parameterName, sqlDbType).Value = item ?? DBNull.Value;
    }

0

Boş bir yöntemle basit bir yöntem kullanıyorum.

    public SqlParameter GetNullableParameter(string parameterName, object value)
    {
        if (value != null)
        {
            return new SqlParameter(parameterName, value);
        }
        else
        {
            return new SqlParameter(parameterName, DBNull.Value);
        }
    }

1
Bu koşullu mantık geriye mi? İlkinde DBNull.Value olmalı mı?
Mark Schultheiss

Elbette öyle. Sabit. Teşekkürler.
Zhi An

0

Kodum, gerçek projede çalışıyor Üçlü operatöre bakmadan önce sqlparametreyi bu benim için en iyi yoldur, bu problemler:

    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);
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.