Pertanyaan System.InvalidCastException: Objek tidak dapat dilemparkan dari DBNull ke tipe lain


Saya memiliki pengecualian dalam kode saya. Saya sudah mencoba mengubah int64 saya ke int32 tetapi itu tidak mengubahnya.

Dalam database, sel-sel yang mewakili "column_ID" memiliki datatype NUMBER.

Masalahnya ada pada baris 7 dalam kode ini:

private void dataGridView_ArticleINVIA_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex >= 0 && e.RowIndex <= (sender as DataGridView).Rows.Count - 1)
    {
        try
        {
            Int64 id_riga = Convert.ToInt64((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value);
            //Exception thrown here:
            int id_macchina = Convert.ToInt32((sender as 
                DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value);
            FormRecipeNote PopUpNote = new FormRecipeNote(id_macchina, 
                "MODIFICA", id_riga, 0);
            PopUpNote.ShowDialog(this);
            PopUpNote.Dispose();
         }
         catch (Exception Exc)
         {
             FormMain.loggerSoftwareClient.Trace(this.Name + " " + Exc);
         }
         //DataGrid_ArticleINVIA();
    }
}

kesalahannya adalah:

System.InvalidCastException: Object cannot be cast from DBNull to other types.
   at System.DBNull.System.IConvertible.ToInt64(IFormatProvider provider)
   at System.Convert.ToInt64(Object value)
   at Software_Client.FormSendReceiveRecipe.dataGridView_ArticleINVIA_CellDoubleClick(Object sender, DataGridViewCellEventArgs e)

Bisakah seseorang membantu saya menyelesaikan ini?


5
2017-12-27 17:34


asal


Jawaban:


Seperti pesan kesalahan mengatakan, nilai sel adalah DBNull.Value dan tidak dapat mengubahnya dari itu menjadi apa pun yang Anda inginkan (dalam hal ini a long atau sebuah int). Anda perlu memeriksa DBNull sebelum mengonversi / mentransmisikan nomor:

Int64 id_riga = 0;
object value = (sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value;
if(value != DBNull.Value) 
    id_riga = Convert.ToInt64(value);

Karena ini menambah biaya overhead yang menjengkelkan, jika Anda melakukan banyak hal ini, Anda mungkin ingin membuat metode penolong yang melakukannya untuk Anda.

public static long? getLongFromDB(object value)
{
    if (value == DBNull.Value) return null;
    return Convert.ToInt64(value);
}

Maka kode Anda bisa:

Int64 id_riga = getLongFromDB((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value)
    .GetValueOrDefault();

7
2017-12-27 17:38



Anda dapat mengubah baris bermasalah menjadi:

int id_macchina = ((sender as DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value as int?).GetValueOrDefault();

Ini akan memberikan nilai default int (0) ke variabel id_macchina jika nilai kolom column_Machine adalah null dalam database (akan DBNull di C #)

Coba ini:

object aa = DBNull.Value;
int a = (aa as int?).GetValueOrDefault();

Itu akan berhasil! nilainya akan menjadi 0 jika kolomnya DBNull.

* EDIT *

Tapi coba gunakan yang lain, ini mungkin menyembunyikan beberapa bug, seperti mengubah tipe data, jika jenisnya panjang dan tidak int dalam database, akan selalu menetapkan 0 ke variabel, itu terjadi dengan saya di masa lalu, berkat @hvd ke untuk menunjukkan itu di komentarnya.


3
2017-12-27 17:36



Saya agak bingung dengan beberapa komentar Anda. Seperti misalnya, di kode Anda, komentar menunjukkan bahwa baris berisi ToInt32 Di sinilah kesalahan terjadi, tetapi pesan kesalahan dengan jelas menunjukkan bahwa kesalahan dilempar dari dalam ToInt64.

Juga, Anda mengatakan bahwa nilai dalam database TIDAK batal. Jika itu benar, Anda tidak akan mendapatkan nilai DBNull, jadi mungkin bermanfaat untuk memperluas kode Anda sedikit sehingga Anda bisa sehingga Anda dapat menempatkan beberapa breakpoint dan memeriksa nilai-nilai dalam sel secara langsung sebelum mencoba untuk mengubahnya.

Saya telah memposting beberapa kode contoh di bawah ini yang dapat Anda gunakan, termasuk fungsi pembantu konversi yang mungkin berguna bagi Anda.

//--------- inside the try block of your event handler -----------//
        var row = (sender as DataGridView).Rows[e.RowIndex];
        object objId = row.Cells["column_ID"].Value;
        object objMachine = row.Cells["column_Machine"].Value;
        // place a breakpoint on the line below, 
                    // so you can inspect the "obj..." values above to see
                    // if they are DBNull or not.

        var id_riga = objId.FromDb<Int64>();
        var id_macchina = objMachine.FromDb<Int32>();
//-----------continue your code here---------//

//----outside the form class, possibly in a separate file -----/
static class DbObjectExtensions {
    public static T FromDb<T>(this object dbObj, T defaultValueIfNull = default(T)) where T : IConvertible {
        if (Convert.IsDBNull(dbObj))
            return defaultValueIfNull;
        if (dbObj is T)
            return (T)dbObj;
        return (T)Convert.ChangeType(dbObj, typeof(T));
    }
}

Saya juga ingin menjernihkan komentar yang saya lihat di atas yang mengatakan "... bukan nol, itu DBNull. Keduanya berbeda". Pernyataan itu benar secara umum, dalam C #, namun sebenarnya menyesatkan dalam konteks yang tertulis. Itu ditulis sebagai tanggapan atas komentar sebelumnya yang mengatakan "[Saya] memeriksa basisdata nilainya dan bukan NULL". Untuk klarifikasi, NULL dalam bidang database IS diwakili oleh DBNull di sebagian besar penyedia database Net. Jadi sebenarnya, nilai NULL dalam database IS biasanya sama dengan DBNull di C #. Jadi jika OP benar dalam mengatakan bahwa nilai database TIDAK NULL, maka itu tidak ikuti bahwa nilai sel seharusnya tidak DBNull.

Tentu saja masih benar null tidak sama dengan DBNull, jadi memeriksa untuk melihat apakah suatu objek adalah null tidak menentukan apakah itu DBNull atau bukan, (tapi bukan itu yang dikatakan OP).

Sebagai catatan terakhir, metode perpanjangan yang saya tulis, FromDB, termasuk parameter opsional untuk nilai kembali default dalam kasus bahwa objek yang dilewatkan adalah DBNull. Ini dapat digunakan sebagai berikut:

//assuming -1 isn't a valid 
var id_riga = objId.FromDb<Int64>(-1); id
if (id_riga == -1) { /*handle case for null db value*/ }

Tergantung pada preferensi pribadi Anda sendiri, paradigma di atas mungkin lebih mudah dipahami daripada versi Nullable yang dijelaskan dalam jawaban lain.


1
2017-12-27 18:25