Pengecualian jika parameter AddWithValue adalah NULL

90

Saya memiliki kode berikut untuk menentukan parameter untuk kueri SQL. Saya mendapatkan pengecualian berikut saat saya menggunakan Code 1; tapi berfungsi dengan baik saat saya gunakan Code 2. Di Code 2kami memiliki pemeriksaan untuk null dan karenanya satu if..elseblok.

Pengecualian:

Kueri berparameter '(@application_ex_id nvarchar (4000)) SELECT E.application_ex_id A' mengharapkan parameter '@application_ex_id', yang tidak disediakan.

Kode 1 :

command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);

Kode 2 :

if (logSearch.LogID != null)
{
         command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
}
else
{
        command.Parameters.AddWithValue("@application_ex_id", DBNull.Value );
}

PERTANYAAN

  1. Bisakah Anda menjelaskan mengapa tidak dapat mengambil NULL dari nilai logSearch.LogID di Kode 1 (tetapi dapat menerima DBNull)?

  2. Apakah ada kode yang lebih baik untuk menangani ini?

Referensi :

  1. Tetapkan null ke SqlParameter
  2. Jenis data yang dikembalikan bervariasi berdasarkan data dalam tabel
  3. Kesalahan konversi dari database smallint ke C # nullable int
  4. Apa gunanya DBNull?

KODE

    public Collection<Log> GetLogs(LogSearch logSearch)
    {
        Collection<Log> logs = new Collection<Log>();

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();

            string commandText = @"SELECT  *
                FROM Application_Ex E 
                WHERE  (E.application_ex_id = @application_ex_id OR @application_ex_id IS NULL)";

            using (SqlCommand command = new SqlCommand(commandText, connection))
            {
                command.CommandType = System.Data.CommandType.Text;

                //Parameter value setting
                //command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
                if (logSearch.LogID != null)
                {
                    command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
                }
                else
                {
                    command.Parameters.AddWithValue("@application_ex_id", DBNull.Value );
                }

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        Collection<Object> entityList = new Collection<Object>();
                        entityList.Add(new Log());

                        ArrayList records = EntityDataMappingHelper.SelectRecords(entityList, reader);

                        for (int i = 0; i < records.Count; i++)
                        {
                            Log log = new Log();
                            Dictionary<string, object> currentRecord = (Dictionary<string, object>)records[i];
                            EntityDataMappingHelper.FillEntityFromRecord(log, currentRecord);
                            logs.Add(log);
                        }
                    }

                    //reader.Close();
                }
            }
        }

        return logs;
    }
LCJ
sumber
3
Apa yang Anda maksud dengan lebih baik? Kode 2 adalah cara yang benar untuk mengirim nilai null ke database.
Phil Gan

Jawaban:

149

Menjengkelkan, bukan.

Kamu bisa memakai:

command.Parameters.AddWithValue("@application_ex_id",
       ((object)logSearch.LogID) ?? DBNull.Value);

Atau sebagai alternatif, gunakan alat seperti "necis", yang akan melakukan semua itu untuk Anda.

Sebagai contoh:

var data = conn.Query<SomeType>(commandText,
      new { application_ex_id = logSearch.LogID }).ToList();

Saya tergoda untuk menambahkan metode yang rapi untuk mendapatkan IDataReader... belum terlalu yakin apakah itu ide yang bagus.

Marc Gravell
sumber
1
Saya berpikir untuk memperpanjang Parametersproperti - apakah itu Object?
Phil Gan
6
@Phil hmmm, ya itu, dan saya mengerti apa yang Anda maksud ... mungkinAddWithValueAndTreatNullTheRightDamnedWay(...)
Marc Gravell
1
@MarcGravell Bisakah Anda menjelaskan mengapa tidak dapat mengambil NULL dari nilai logSearch.LogID di Kode 1 (tetapi dapat menerima DBNull)?
LCJ
18
@ Lijo karena nulldalam nilai parameter berarti "jangan kirim parameter ini". Saya curiga itu adalah keputusan yang buruk yang langsung saja terjadi. Faktanya, saya pikir sebagian besar DBNulladalah keputusan yang pada dasarnya buruk yang terjadi: stackoverflow.com/a/9632050/23354
Marc Gravell
1
@tylerH karena aturan cor coale null - yang mungkin melemah di C # 9
Marc Gravell
52

Saya merasa lebih mudah untuk hanya menulis metode ekstensi untuk SqlParameterCollectionyang menangani nilai null:

public static SqlParameter AddWithNullableValue(
    this SqlParameterCollection collection,
    string parameterName,
    object value)
{
    if(value == null)
        return collection.AddWithValue(parameterName, DBNull.Value);
    else
        return collection.AddWithValue(parameterName, value);
}

Kemudian Anda sebut saja seperti:

sqlCommand.Parameters.AddWithNullableValue(key, value);
Neksus aksiomatik
sumber
nilai bisa int atau int ?, string, bool atau bool ?, DateTime atau Datetime? , dll?
Kiquenet
3
Saya membaca jawaban Marc dan berpikir "Saya pikir saya lebih suka menulis metode ekstensi untuk koleksi Parameter", lalu saya menggulir ke bawah rambut ... (hal yang baik tentang metode ekstensi adalah saya dapat melakukan satu kali temukan / ganti setelah dan semua pembaruan kode saya selesai)
jleach
1
Solusi hebat ... Metode ekstensi harus ditentukan dalam kelas statis. Cara: Menerapkan dan Memanggil Metode Ekstensi Kustom
Chris Catignani
2
Mungkin saya salah (jenis pemula C #) tetapi tidak bisakah Anda melakukannya lebih ringkas seperti ini:return collection.AddWithValue(parameterName, value ?? DBNull.Value);
Tobias Feil
1
@TobiasFeil Ya, Anda juga bisa melakukannya. Itu hanya soal selera.
AxiomaticNexus
4

Untuk berjaga-jaga jika Anda melakukan ini sambil memanggil prosedur tersimpan: Saya pikir lebih mudah dibaca jika Anda mendeklarasikan nilai default pada parameter dan menambahkannya hanya jika diperlukan.

SQL:

DECLARE PROCEDURE myprocedure
    @myparameter [int] = NULL
AS BEGIN

C #:

int? myvalue = initMyValue();
if (myvalue.hasValue) cmd.Parameters.AddWithValue("myparamater", myvalue);
z00l
sumber
0

beberapa masalah, diizinkan dengan perlu mengatur SQLDbType

command.Parameters.Add("@Name", SqlDbType.NVarChar);
command.Parameters.Value=DBNull.Value

di mana SqlDbType.NVarChar Anda ketik. Harus mengatur tipe SQL.

pengguna1599225
sumber