Eccezione quando il parametro AddWithValue è NULL


89

Ho il seguente codice per specificare i parametri per la query SQL. Ottengo la seguente eccezione quando uso Code 1; ma funziona bene quando lo uso Code 2. In Code 2abbiamo un controllo per null e quindi un if..elseblocco.

Eccezione:

La query parametrizzata '(@application_ex_id nvarchar (4000)) SELECT E.application_ex_id A' prevede il parametro '@application_ex_id', che non è stato fornito.

Codice 1 :

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

Codice 2 :

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

DOMANDA

  1. Puoi spiegare perché non è in grado di prendere NULL dal valore logSearch.LogID nel codice 1 (ma in grado di accettare DBNull)?

  2. Esiste un codice migliore per gestirlo?

Riferimento :

  1. Assegna null a un SqlParameter
  2. Il tipo di dati restituito varia in base ai dati nella tabella
  3. Errore di conversione dal database smallint in C # nullable int
  4. Qual è il punto di DBNull?

CODICE

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

3
Cosa intendi per migliore? Il codice 2 è il modo corretto per inviare un valore null a un database.
Phil Gan

Risposte:


148

Fastidioso, non è vero?

Puoi usare:

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

O in alternativa, usa uno strumento come "dapper", che farà tutto questo casino per te.

Per esempio:

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

Sono tentato di aggiungere un metodo a dapper per ottenere il IDataReader... non ancora sicuro se sia una buona idea.


1
Stavo pensando a un'estensione della Parametersproprietà - è un Object?
Phil Gan

6
@Phil hmmm, sì lo è, e capisco cosa intendi ... forseAddWithValueAndTreatNullTheRightDamnedWay(...)
Marc Gravell

1
@MarcGravell Puoi spiegare perché non è in grado di prendere NULL dal valore logSearch.LogID nel codice 1 (ma in grado di accettare DBNull)?
LCJ

18
@ Lijo perché nullin un parametro il valore significa "non inviare questo parametro". Sospetto che sia stata una decisione sbagliata che è stata semplicemente presa. In effetti, penso che la maggior parte sia DBNullstata una decisione fondamentalmente sbagliata che è stata
incastrata

1
@tylerH a causa delle regole del cast di null coale - che potrebbero indebolirsi in C # 9
Marc Gravell

52

Trovo più semplice scrivere un metodo di estensione per il SqlParameterCollectionche gestisce i valori nulli:

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

Quindi lo chiami come:

sqlCommand.Parameters.AddWithNullableValue(key, value);

il valore può essere int o int ?, string, bool o bool ?, DateTime o Datetime? , eccetera ?
Kiquenet

3
Ho letto la risposta di Marc e ho pensato "Penso che preferirei scrivere un metodo di estensione per la raccolta Parameters", quindi ho fatto scorrere un capello ... (la cosa bella di un metodo di estensione è che posso fare una singola ricerca / sostituzione dopo e tutti gli aggiornamenti del codice sono stati completati)
jleach

1
Ottima soluzione ... I metodi di estensione devono essere definiti in una classe statica. Procedura: implementare e chiamare un metodo di estensione personalizzato
Chris Catignani

2
Forse mi sbaglio (una specie di principiante di C #) ma non potresti farlo in modo più conciso in questo modo:return collection.AddWithValue(parameterName, value ?? DBNull.Value);
Tobias Feil

1
@TobiasFeil Sì, potresti farlo anche tu. È solo questione di gusti.
AxiomaticNexus

4

Nel caso in cui lo stai facendo durante la chiamata di una stored procedure: penso che sia più facile da leggere se dichiari un valore predefinito sul parametro e lo aggiungi solo quando necessario.

SQL:

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

C #:

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

0

qualche problema, consentito con Necessariamente impostato SQLDbType

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

dove SqlDbType.NVarChar digiti. Impostare necessariamente il tipo SQL.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.