Tetapkan null ke SqlParameter

189

Kode berikut memberikan kesalahan - "Tidak ada konversi implisit dari DBnull ke 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;
Relativitas
sumber
4
Anda harus menggunakan AgeItem.AgeIndex ke objek yang saya pikir ... stackoverflow.com/questions/202271/… (btw, mengapa ==di akhir baris ke-3?)
Greg

Jawaban:

341

Masalahnya adalah bahwa ?:operator tidak dapat menentukan jenis kembali karena Anda baik mengembalikan intnilai atau nilai jenis DBNull, yang tidak kompatibel.

Anda tentu saja dapat menggunakan instance dari AgeIndex menjadi tipe objectyang akan memenuhi ?:persyaratan.

Anda dapat menggunakan ??operator penggabungan nol sebagai berikut

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

Berikut ini kutipan dari dokumentasi MSDN untuk ?:operator yang menjelaskan masalahnya

Jenis first_expression dan second_expression harus sama, atau konversi implisit harus ada dari satu jenis ke yang lain.

Chris Taylor
sumber
Mengapa tidak ada pengecualian yang dilemparkan ketika mencoba melemparkan null ke objek? Saya pikir itu seharusnyaAgeItem.AgeIndex as object
Niels Brinch
@Niels Brinch, tidak akan ada pengecualian karena null adalah objek dan selama Anda tidak mencoba dereferensi, itu sah-sah saja. Namun, dalam contoh ini bukan nol yang dilemparkan ke objek, itu DBNull.Value yang sebenarnya merupakan tipe nilai. Itu ?? operator mengatakan 'jika AgetItem.AgeIndex adalah null maka kembalilah DBNull.Value sebaliknya returen AgeItem.AgeIndex' maka respons dilemparkan ke objek. Lihat operator penggabungan nol untuk detail lebih lanjut. msdn.microsoft.com/en-us/library/ms173224.aspx
Chris Taylor
3
Secara teknis, solusi Anda menggunakan operator null-penggabungan ??adalah solusi yang sama seperti jika Anda menggunakan terner biasa ?:- Anda masih perlu pemain AgeItem.AgeIndexke objek: planIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;.
newfurniturey
Jika Anda menggunakan terner biasa ?:untuk melakukan perbandingan tipe-spesifik, maka casting seluruh ekspresi tidak akan berhasil. Anda harus menggunakan parameter non-dbnull seperti:someID == 0 ? DBNull.Value : (object)someID
ingredient_15939
Itu benar tetapi jika Anda perlu menggunakan nilai null-bisa sebagai parameter masuk fungsi yang menghasilkan mengkonsumsi SqlParameter dan jika itu nol Anda punya kesalahan cara ini tidak berfungsi dan Anda harus menggunakan cara If-Else yang sederhana. misalnya: sample.Text.Trim ()! = ""? func (sample.Text): DBNull.Value; tidak akan berfungsi sebagai?: dan ??
QMaster
105

Jawaban yang diterima menyarankan penggunaan gips. Namun, sebagian besar tipe SQL memiliki bidang Null khusus yang dapat digunakan untuk menghindari gips ini.

Misalnya, SqlInt32.Null"Merupakan DBNull yang dapat ditugaskan untuk instance kelas SqlInt32 ini."

int? example = null;
object exampleCast = (object) example ?? DBNull.Value;
object exampleNoCast = example ?? SqlInt32.Null;
Brian
sumber
2
Saran itu tampak menjanjikan jadi saya mencoba "System.Data.SqlTypes.SqlString.Null" tetapi tidak berhasil. Ini menempatkan string aktual dari "Null" ('N', 'u', 'l', 'l') ke dalam bidang alih-alih membiarkannya kosong dengan true (null). Namun, "jawaban diterima" lama 2010 yang menggunakan pemain dengan (objek) ?? DBNull.Value bekerja dengan benar. (Penyedia ADO.NET yang saya gunakan adalah SQLite tapi saya tidak yakin apakah itu membuat perbedaan.) Saya menyarankan orang lain dengan hati-hati menguji tip Brian untuk memastikan perilaku nol berfungsi seperti yang diharapkan.
JasDev
6
@JasDev: Saya samar-samar ingat menggambarkan trik ini dalam komentar kepada pengguna rep tinggi (saya pikir Marc Gravell) dan diberitahu itu hanya bekerja di Microsoft SQL Server.
Brian
@JasDev penyedia akan perbedaan ini berfungsi di SQL Server sebagai titik Brain.
Lankymart
Jawaban ini hanya menggantikan pemain eksplisit ke objek dengan implisit.one. Dalam kode sampel, exampleNoCastdideklarasikan objek, sehingga gips ke objek masih terjadi. Jika, seperti dalam kode OP, nilainya diberikan langsung ke SqlParameter.Value yang juga merupakan tipe objek, maka Anda masih mendapatkan pemeran.
Scott
31

Anda perlu meneruskan DBNull.Valuesebagai parameter nol dalam perintah SQLC, kecuali jika nilai standar ditentukan dalam prosedur tersimpan (jika Anda menggunakan prosedur tersimpan). Pendekatan terbaik adalah menetapkan DBNull.Valueuntuk parameter yang hilang sebelum eksekusi permintaan, dan mengikuti setiap langkah akan melakukan pekerjaan.

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

Kalau tidak ubah baris ini:

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

Sebagai berikut:

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

Karena Anda tidak dapat menggunakan jenis nilai yang berbeda dalam pernyataan bersyarat, karena DBNull dan int berbeda satu sama lain. Semoga ini bisa membantu.

ShahidAzim
sumber
Jawaban ini sangat bagus karena merupakan contoh dalam segala hal yang mungkin. Saya suka pendekatan pertama, saya biasanya menggunakan EF tetapi dalam persyaratan ini tidak bisa melakukannya dan saya menghemat banyak waktu. Terima kasih!
Leandro
23

Dengan satu baris kode, coba ini:

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

Coba ini:

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
sumber
5

Jika Anda menggunakan operator kondisional (ternary) kompiler memerlukan konversi implisit antara kedua jenis, jika tidak, Anda akan mendapatkan pengecualian.

Jadi Anda bisa memperbaikinya dengan melemparkan salah satu dari keduanya ke System.Object:

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

Tetapi karena hasilnya tidak terlalu cantik dan Anda harus selalu mengingat casting ini, Anda bisa menggunakan metode ekstensi seperti itu:

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

Kemudian Anda dapat menggunakan kode ringkas ini:

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue();
Tim Schmelter
sumber
1

Menurut pendapat saya, cara yang lebih baik adalah melakukan ini dengan properti Parameters dari kelas SqlCommand :

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

sumber
Tetapi jika nilainya DBNull.Value, ADO.NET mungkin agak kesulitan menebak SqlDbType apa yang mungkin ........ ini nyaman - tapi agak berbahaya ....
marc_s
1

Pertimbangkan untuk menggunakan struktur Nullable (T) yang tersedia. Ini akan membiarkan Anda hanya menetapkan nilai jika Anda memilikinya, dan objek Perintah SQL Anda akan mengenali nilai yang dapat dibatalkan dan memproses sesuai tanpa kerumitan di ujung Anda.

Kanwar Singh
sumber
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;
}
Anil Kumar
sumber
0

Coba ini:

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

Dengan kata lain, jika parameternya nol, jangan kirimkan ke proc Anda yang tersimpan (dengan asumsi, tentu saja, proc yang disimpan menerima parameter nol yang tersirat dalam pertanyaan Anda).

Flipster
sumber
Tapi sekarang, Anda hanya menghilangkan parameter - Saya sangat meragukan prosedur tersimpan akan senang tentang ini .... kemungkinan besar, panggilan akan gagal menyatakan "tidak ada nilai untuk parameter @AgeIndex yang disediakan yang diharapkan" .... .
marc_s
Wow. Keras. Tulis saja proc yang disimpan ke default ke nilai jika parameter tidak lulus (@AgeIndex int = 0). Terjadi sepanjang waktu. Klien dapat menerima default, atau menimpanya dengan melewatkan parameter. Mengapa downvote?
Flipster
0

coba sesuatu seperti ini:

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

Saya memecahkan seperti itu.

A Sinan Direk
sumber
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);
Anil Kumar
sumber
0

Inilah yang saya lakukan ...

        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();
Tom Mack
sumber
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
sumber
0

Metode ekstensi sederhana untuk ini adalah:

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

Saya menggunakan metode sederhana dengan cek nol.

    public SqlParameter GetNullableParameter(string parameterName, object value)
    {
        if (value != null)
        {
            return new SqlParameter(parameterName, value);
        }
        else
        {
            return new SqlParameter(parameterName, DBNull.Value);
        }
    }
Zhi An
sumber
1
Apakah itu logika kondisional mundur? Haruskah DBNull.Value berada di yang pertama?
Mark Schultheiss
Tentunya begitu. Tetap. Terima kasih.
Zhi An
0

Kode saya, bekerja dalam proyek nyata. Lihatlah operator ternary sebelum membuat sqlparameter ini adalah cara terbaik bagi saya, tanpa masalah:

    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);
    }
Ibngel Ibáñez
sumber