2009-05-14 9 views
22

Ich habe eine SQL-Abfrage, die einen Parameter hat, der in der Datenbank (Sql Server) Null sein kann. Die Aktualisierungsmethode funktioniert ordnungsgemäß, bis der Benutzer ein leeres Feld in das Feld einfügt. Dadurch wird ein Nullwert für das DataTime-Objekt erzeugt (dieses Objekt ist nullfähig). Das Problem ist, wenn die dbCommand.ExecuteNonQuery();.SqlParameter mit Nullable Wert geben Fehler während ExecuteNonQuery?

Hier ist, wie ich die Parameter für dieses Feld bauen:

IDataParameter dbParam_au_id = new SqlParameter(); 
    dbParam_au_id.ParameterName = "@birthday"; 
    dbParam_au_id.Value = birthday; 
    dbParam_au_id.DbType = DbType.DateTime; 
    dbCommand.Parameters.Add(dbParam_au_id); 

Ich habe versuchen, den Nullwert von Geburtstag zu konvertieren, so zu DBNull.Value:

IDataParameter dbParam_au_id = new SqlParameter(); 
    dbParam_au_id.ParameterName = "@birthday"; 
    dbParam_au_id.Value = birthday??DBNull.Value; 
    dbParam_au_id.DbType = DbType.DateTime; 
    dbCommand.Parameters.Add(dbParam_au_id); 

Aber diesen Code gewonnen 't compile und ich bekomme Fehler:

Fehler 1 Operator' ?? ' kann nicht auf Operanden vom Typ 'System.DateTime' angewendet werden und 'System.DBNull'

Irgendeine Idee?

+0

Als Randnotiz empfehle ich dringend, dass Sie die DbType-Eigenschaft nicht festlegen, es sei denn, Sie verwenden es als Ausgabeparameter. Ich habe noch nie unzählige subtile Fehler gesehen, die durch den Einsatz eines einzigen gelöst wurden. –

Antwort

51

Die Typen sind nicht kompatibel. Probieren Sie etwas wie folgt aus:

dbParam_au_id.Value = (object)birthday ?? DBNull.Value; 
13

Wenn die SqlParameter Klasse beim ersten Mal korrekt geschrieben wurde ... ein C# Nullwert als DBNull.Value behandelt werden würde. Das wäre intuitiv, daher ist das Setzen eines SqlParameter-Wertes auf null funktionell äquivalent zum Entfernen aus der SqlParameterCollection.

Um diesen lächerlichen API-Entwurfsfehler zu korrigieren, erstellen Sie Ihre eigene AddParameter-Methode (mit Überladungen), die eine SqlParameterCollection, eine Zeichenfolge (Parametername) und ein Objekt (Parameterwert) verwendet.

#region Add by Name/Value. 
/// <summary> 
/// Adds an input parameter with a name and value. Automatically handles conversion of null object values to DBNull.Value. 
/// </summary> 
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param> 
/// <param name="name">The name of the parameter to add.</param> 
/// <param name="value">The value of the parameter to add.</param> 
private static void AddParameter(SqlParameterCollection parameters, string name, object value) 
{ 
    parameters.Add(new SqlParameter(name, value ?? DBNull.Value)); 
} 

/// <summary> 
/// Adds a parameter with a name and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value. 
/// </summary> 
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param> 
/// <param name="name">The name of the parameter to add.</param> 
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param> 
/// <param name="direction">The ParameterDirection of the parameter to add (input, output, input/output, or return value).</param> 
private static void AddParameter(SqlParameterCollection parameters, string name, object value, ParameterDirection direction) 
{ 
    SqlParameter parameter = new SqlParameter(name, value ?? DBNull.Value); 
    parameter.Direction = direction; 
    parameters.Add(parameter); 
} 
#endregion 

#region Add by Name, Type, and Value. 
/// <summary> 
/// Adds an input parameter with a name, type, and value. Automatically handles conversion of null object values to DBNull.Value. 
/// </summary> 
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param> 
/// <param name="name">The name of the parameter to add.</param> 
/// <param name="type">Specifies the SqlDbType of the parameter.</param> 
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param> 
private static void AddParameter(SqlParameterCollection parameters, string name, SqlDbType type, object value) 
{ 
    AddParameter(parameters, name, type, 0, value ?? DBNull.Value, ParameterDirection.Input); 
} 

/// <summary> 
/// Adds a parameter with a name, type, and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value. 
/// </summary> 
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param> 
/// <param name="name">The name of the parameter to add.</param> 
/// <param name="type">Specifies the SqlDbType of the parameter.</param> 
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param> 
/// <param name="direction">The ParameterDirection of the parameter to add (input, output, input/output, or return value).</param> 
private static void AddParameter(SqlParameterCollection parameters, string name, SqlDbType type, object value, ParameterDirection direction) 
{ 
    AddParameter(parameters, name, type, 0, value ?? DBNull.Value, direction); 
} 
#endregion 

#region Add by Name, Type, Size, and Value. 
/// <summary> 
/// Adds an input parameter with a name, type, size, and value. Automatically handles conversion of null object values to DBNull.Value. 
/// </summary> 
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param> 
/// <param name="name">The name of the parameter to add.</param> 
/// <param name="type">Specifies the SqlDbType of the parameter.</param> 
/// <param name="size">Specifies the size of the parameter for parameter types of variable size. Set to zero to use the default size.</param> 
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param> 
private static void AddParameter(SqlParameterCollection parameters, string name, SqlDbType type, int size, object value) 
{ 
    AddParameter(parameters, name, type, size, value ?? DBNull.Value, ParameterDirection.Input); 
} 

/// <summary> 
/// Adds a parameter with a name, type, size, and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value. 
/// </summary> 
/// <param name="parameters">SqlParameterCollection from an SqlCommand instance.</param> 
/// <param name="name">The name of the parameter to add.</param> 
/// <param name="type">Specifies the SqlDbType of the parameter.</param> 
/// <param name="size">Specifies the size of the parameter for parameter types of variable size. Set to zero to use the default size.</param> 
/// <param name="value">The value of the parameter to add. If null, this is automatically converted to DBNull.Value.</param> 
/// <param name="direction">The ParameterDirection of the parameter to add (input, output, input/output, or return value).</param> 
private static void AddParameter(SqlParameterCollection parameters, string name, SqlDbType type, int size, object value, ParameterDirection direction) 
{ 
    SqlParameter parameter; 
    if (size < 1) 
     parameter = new SqlParameter(name, type); 
    else 
     parameter = new SqlParameter(name, type, size); 
    parameter.Value = value ?? DBNull.Value; 
    parameter.Direction = direction; 
    parameters.Add(parameter); 
} 
#endregion 

Wie Sie sehen können, innerhalb dieser Methode (und Überlastungen), wobei der Wert bereits als Objekt typisiert ist, verwende ich die „Wert ?? DBNull.Value“ Anweisung der Nullen zu erzwingen = DBNull.Value Regel.

Wenn Sie jetzt Nullobjektverweise oder Nullable-Typen ohne Werte an Ihre AddParameter-Methode übergeben, erhalten Sie das erwartete, intuitive Verhalten, bei dem ein DBNull.Value an die Abfrage übergeben wird.

Ich kann mir nicht vorstellen, warum die API so implementiert wurde, denn wenn ich wollte, dass ein Parameter ignoriert würde, würde ich ihn nicht hinzufügen und dann seinen Wert auf null setzen. Ich würde es entweder nicht hinzufügen, oder ich würde es aus der SqlParameterCollection entfernen. Wenn ich einen Parameter HINZUFÜGE und seinen Wert festlege (selbst wenn er auf Null gesetzt ist), erwarte ich, dass er in der Abfrage BENUTZT wird. Ich erwarte, dass null einen Nullwert bedeutet.

Ich habe gehört, dass sie es aus Leistungsgründen nicht "korrekt" implementiert haben, aber das ist lächerlich, wie demonstriert, da das Aufrufen von SqlParameterCollection.AddWithValue-Methode sowieso alles in ein Objekt konvertiert und eine Nullable-Instanz mit Nein konvertiert Der Wert für ein Null-Objekt ist ein wesentlicher Teil der C# -Sprache, der überhaupt kein Leistungshit ist. Microsoft sollte das wirklich beheben.

+1

nette Reihe von Dienstprogrammfunktionen. Wenn Sie in 3.5 oder höher sind, können Sie diese als Erweiterungen der SqlParameterCollection anpassen und Sie haben command.Paramters.AddParameter (...) Erfahrung – Roman

+0

Sieben Jahre später ist dies immer noch das Verhalten der Add-Methode SqlParameterCollection.Verwenden Sie diese Lösung noch? Ich frage mich nur, ob in der Zwischenzeit eine bessere Lösung hinzugekommen ist. Ich benutze zur Zeit AddRange mit einem Parameter-Array, also muss ich das Array durchlaufen und den Wert jedes einzelnen ersetzen, wenn null ... – Doug

Verwandte Themen