I have an sql query that has a parameter that can be null in the database (Sql Server). The update method work fine until that user put a blank in the field, this produce a
If the SqlParameter class was written correctly the first time... a C# null value would be handled as DBNull.Value. That would be intuitive, so OF COURSE setting an SqlParameter value to null is functionally equivalent to removing it from the SqlParameterCollection.
To correct this ridiculous API design error, create your own AddParameter method (with overloads), which takes a SqlParameterCollection, a String (parameter name), and an Object (parameter value).
#region Add by Name/Value.
///
/// Adds an input parameter with a name and value. Automatically handles conversion of null object values to DBNull.Value.
///
/// SqlParameterCollection from an SqlCommand instance.
/// The name of the parameter to add.
/// The value of the parameter to add.
private static void AddParameter( SqlParameterCollection parameters, string name, object value )
{
parameters.Add( new SqlParameter( name, value ?? DBNull.Value ) );
}
///
/// Adds a parameter with a name and value. You specify the input/output direction. Automatically handles conversion of null object values to DBNull.Value.
///
/// SqlParameterCollection from an SqlCommand instance.
/// The name of the parameter to add.
/// The value of the parameter to add. If null, this is automatically converted to DBNull.Value.
/// The ParameterDirection of the parameter to add (input, output, input/output, or return value).
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.
///
/// Adds an input parameter with a name, type, and value. Automatically handles conversion of null object values to DBNull.Value.
///
/// SqlParameterCollection from an SqlCommand instance.
/// The name of the parameter to add.
/// Specifies the SqlDbType of the parameter.
/// The value of the parameter to add. If null, this is automatically converted to DBNull.Value.
private static void AddParameter( SqlParameterCollection parameters, string name, SqlDbType type, object value )
{
AddParameter( parameters, name, type, 0, value ?? DBNull.Value, ParameterDirection.Input );
}
///
/// 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.
///
/// SqlParameterCollection from an SqlCommand instance.
/// The name of the parameter to add.
/// Specifies the SqlDbType of the parameter.
/// The value of the parameter to add. If null, this is automatically converted to DBNull.Value.
/// The ParameterDirection of the parameter to add (input, output, input/output, or return value).
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.
///
/// Adds an input parameter with a name, type, size, and value. Automatically handles conversion of null object values to DBNull.Value.
///
/// SqlParameterCollection from an SqlCommand instance.
/// The name of the parameter to add.
/// Specifies the SqlDbType of the parameter.
/// Specifies the size of the parameter for parameter types of variable size. Set to zero to use the default size.
/// The value of the parameter to add. If null, this is automatically converted to DBNull.Value.
private static void AddParameter( SqlParameterCollection parameters, string name, SqlDbType type, int size, object value )
{
AddParameter( parameters, name, type, size, value ?? DBNull.Value, ParameterDirection.Input );
}
///
/// 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.
///
/// SqlParameterCollection from an SqlCommand instance.
/// The name of the parameter to add.
/// Specifies the SqlDbType of the parameter.
/// Specifies the size of the parameter for parameter types of variable size. Set to zero to use the default size.
/// The value of the parameter to add. If null, this is automatically converted to DBNull.Value.
/// The ParameterDirection of the parameter to add (input, output, input/output, or return value).
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
As you can see, inside that method (and overloads), where the value is already typed as an object, I use the "value ?? DBNull.Value" statement to enforce the null = DBNull.Value rule.
Now, when you pass null object references or nullable types with no values to your AddParameter method, you get the expected, intuitive behavior, where a DBNull.Value is passed to the query.
I can't imagine why the API was implemented as it is, because if I wanted a parameter to be ignored, I would not ADD it and then SET it's value to null. I would either NOT add it in the first place, or I would REMOVE it from the SqlParameterCollection. If I ADD a parameter, and SET it's value (even if set to null), I expect it to be USED in the query, I expect null to mean null value.
I've heard they didn't implement it the "correct" way for performance reasons, but that's ridiculous, as demonstrated, because calling SqlParameterCollection.AddWithValue method converts everything to an object anyway, and converting a Nullable instance with no value to a null object is an intrinsic part of the C# language which is not a performance hit at all. Microsoft should really fix this.