Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SqlParameter with Nullable value give error while ExecuteNonQuery?

Tags:

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 null value for the DataTime object (this object is nullable). The problem is when the dbCommand.ExecuteNonQuery();.

Here is how I build the parameter for this field:

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

I have try to convert the null value of birthday to DBNull.Value like that :

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

But this code won't compile and I get error :

Error 1 Operator '??' cannot be applied to operands of type 'System.DateTime?' and 'System.DBNull'

Any idea?

like image 413
Patrick Desjardins Avatar asked May 14 '09 13:05

Patrick Desjardins


People also ask

Why do we use Nullable in C#?

The Nullable type allows you to assign a null value to a variable. Nullable types introduced in C#2.0 can only work with Value Type, not with Reference Type. The nullable types for Reference Type is introduced later in C# 8.0 in 2019 so that we can explicitly define if a reference type can or can not hold a null value.

What is nullable int default value?

The default value of a nullable value type represents null , that is, it's an instance whose Nullable<T>. HasValue property returns false .

What is nullable value in C#?

In C#, Nullable is a concept that allows a type to hold an additional value null. In other words, we can make a variable Nullable, so, it can hold additional null value. All Nullable variables are the instances of System.

What is nullable?

A type is said to be nullable if it can be assigned a value or can be assigned null , which means the type has no value whatsoever. By default, all reference types, such as String, are nullable, but all value types, such as Int32, are not.


2 Answers

The types are not compatible. Try something like this:

dbParam_au_id.Value = (object)birthday ?? DBNull.Value; 
like image 178
David M Avatar answered Sep 21 '22 00:09

David M


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. /// <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 

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.

like image 26
Triynko Avatar answered Sep 17 '22 00:09

Triynko