Apa praktik terbaik untuk menangani null int/char dari Database SQL?

Saya memiliki database yang menyimpan profil opsional pengguna. Di profil saya memiliki string, char (untuk M atau F) dan int.

Saya mengalami masalah saat mencoba memasukkan jenis kelamin pengguna ke dalam properti objek Profil saya, dan aplikasi mogok karena tidak tahu cara menangani nilai nol yang dikembalikan.

Saya sudah mencoba memasukkan data ke tipe yang sesuai

char sex = (char)dt.Rows[0]["Sex"];

Itu tidak menyelesaikan masalah saya. Saya kemudian mencoba mengubah tipenya menjadi Nullable dan Nullable dan tetap mendapatkan masalah konversi. Solusi saya saat ini yang dapat saya temukan adalah sebagai berikut:

object.sex = null;  
if(dt.Rows[0]["Sex"] != DBNull.Value)
      object.sex = (char)dt.Rows[0]["Sex"];
object.WorkExt = null;
if(dt.Rows[0]["WorkExt"] != DBNull.Value)
      object.WorkExt = (int)dt.Rows[0]["WorkExt"];

Apakah ada cara yang lebih sederhana atau lebih baik untuk melakukan ini? Atau apakah saya sudah berada di jalur yang benar?


person Matt R    schedule 25.11.2008    source sumber


Jawaban (6)


jawaban rotard (gunakan Is<ColumnName>Null()) hanya berfungsi untuk kumpulan data yang diketik.

Untuk kumpulan data yang tidak diketik, Anda harus menggunakan salah satu pola dalam kode berikut. Jika kode ini belum pasti, beri tahu saya dan saya akan mengeditnya sampai benar. Ini adalah pertanyaan yang sangat umum dan hanya ada satu jawaban yang benar.

using System.
using System.Data;

class Program
{
    static void Main(string[] args)
    {
        DataTable dt = new DataTable();
        dt.Columns.Add("test", typeof (char));
        dt.Columns["test"].AllowDBNull = true;

        DataRow dr = dt.Rows.Add();
        char? test;

        try
        {
            test = (char?)dr["test"];
        }
        catch (InvalidCastException)
        {
            Console.WriteLine("Simply casting to a nullable type doesn't work.");
        }

        test  = dr.Field<char?>("test");
        if (test == null)
        {
            Console.WriteLine("The Field extension method in .NET 3.5 converts System.DBNull to null.");                
        }

        test = (dr["test"] is DBNull) ? null : (char?) dr["test"];
        if (test == null)
        {
            Console.WriteLine("Before .NET 3.5, you have to check the type of the column's value.");
        }

        test = (dr["test"] == DBNull.Value) ? null : (char?) dr["test"];
        if (test == null)
        {
            Console.WriteLine("Comparing the field's value to DBNull.Value is very marginally faster, but takes a bit more code.");
        }

        // now let's put the data back

        try
        {
            dr["test"] = test;
        }
        catch (ArgumentException)
        {
            Console.WriteLine("You can't set nullable columns to null.");
        }

        dr.SetField("test", test);
        if (dr["test"] is DBNull)
        {
            Console.WriteLine("Again, in .NET 3.5 extension methods make this relatively easy.");
        }

        dr["test"] = (object)test ?? DBNull.Value;
        if (dr["test"] is DBNull)
        {
            Console.WriteLine("Before .NET 3.5, you can use the null coalescing operator, but note the awful cast required.");
        }


        Console.ReadLine();
    }
}
person Robert Rossney    schedule 25.11.2008

tipe nullable dirancang hanya untuk tujuan ini! gunakan 'sebagai karakter?' bukannya '(karakter?)'

class Foo {
    char? sex;
}
Foo object;

object.sex = dt.Rows[0]["Sex"] as char?;
person Jimmy    schedule 25.11.2008
comment
Sayangnya, tipe nullable tidak dirancang untuk ini, seperti yang akan Anda temukan jika Anda menguji kode itu. Jika DataColumn memiliki set AllowDBNull, nilai null di kolom tersebut adalah DBNull.Value, bukan null. Kode Anda memunculkan InvalidCastException. - person Robert Rossney; 26.11.2008
comment
sejak kapan 'sebagai' melempar InvalidCastException? - person Jimmy; 26.11.2008

Diskusi yang layak mengenai hal ini ada di Cara paling efisien untuk memeriksa DBNull dan kemudian menetapkannya ke variabel?.

person BQ.    schedule 25.11.2008
comment
Itu sedikit berbeda, karena itu tidak menimpa nilai yang ada dengan DBNull - person Jimmy; 26.11.2008

bagaimana tentang:

    internal static T CastTo<T>(object value)
    {
        return value != DBNull.Value ? (T)value : default(T);
    }

dan kemudian menggunakannya seperti:

        return new EquipmentDetails(
            CastTo<int>(reader["ID"]),
            CastTo<int>(reader["CategoryID"]),
            CastTo<string>(reader["Description"]));

dll...

person Community    schedule 26.11.2008

Apakah ini merupakan tabel data ADO.Net 2? Bisakah kamu tidak melakukan sesuatu seperti:

if(dt.Rows[0].IsSexNull()) {} else {}

? Selain itu, dengan asumsi Anda memiliki kendali atas database Anda, bukankah lebih masuk akal jika menggunakan bit, dibandingkan string?

person gillonba    schedule 25.11.2008
comment
Ada orang-orang bingung di luar sana yang benar-benar tidak tahu bagaimana menjawab pertanyaan itu, dan ada pula yang tidak suka memberi tahu Anda. Anda dapat menggabungkan kelompok-kelompok tersebut, tetapi setidaknya diperlukan opsi ketiga. - person Joel Coehoorn; 25.11.2008
comment
Masalah yang jelas dalam menggunakan bit adalah meskipun Sex adalah pilihan biner, tidak jelas apa arti Benar dan Salah. Selain itu, ini bahkan bukan pilihan terner di banyak sistem: sistem yang saya gunakan mendukung Pria, Wanita, Tidak Diketahui, dan Tolak Status. Dan NULL, yang tidak sama dengan Unknown. - person Robert Rossney; 27.11.2008

Saya akan melakukannya seperti yang Anda lakukan. Saya akan menulis fungsi untuk itu:

Sesuatu yang berfungsi:

object.sex = handle(dt.Rows[0]["Sex"]);

Dan dalam penanganannya Anda melakukan pemeriksaan ==DBNull.Value.

person Burkhard    schedule 25.11.2008
comment
Itu hanya berfungsi jika fungsi Anda mengembalikan objek, dan Anda memberikan nilai kembalian ke char? dalam tugas. Metode Bidang di ekstensi DataRow .NET 3.5 melakukan ini untuk Anda. - person Robert Rossney; 26.11.2008