具有Nullable值的SqlParameter在ExecuteNonQuery时给出错误?

我有一个SQL查询,其参数在数据库(Sql Server)中可以为null。 更新方法正常工作,直到该用户在字段中放置一个空白,这将为DataTime对象生成一个空值(此对象可以为空)。 问题是当dbCommand.ExecuteNonQuery();

以下是我为此字段构建参数的方法:

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

我尝试将生日的null值转换为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); 

但是这段代码不能编译,我得到错误:

错误1运算符’??’ 不能应用于’System.DateTime?’类型的操作数 和’System.DBNull’

任何的想法?

类型不兼容。 尝试这样的事情:

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

如果第一次正确写入SqlParameter类… C#null值将作为DBNull.Value处理。 这很直观,所以OF COURSE将SqlParameter值设置为null在function上等同于从SqlParameterCollection中删除它。

要纠正这个荒谬的API设计错误,请创建自己的AddParameter方法(带有重载),该方法采用SqlParameterCollection,String(参数名称)和Object(参数值)。

 #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 

正如您所看到的,在该方法(和重载)中,值已经作为对象输入,我使用“value ?? DBNull.Value”语句来强制执行null = DBNull.Value规则。

现在,当您将没有值的空对象引用或可空类型传递给AddParameter方法时,您将获得预期的直观行为,其中DBNull.Value将传递给查询。

我无法想象为什么API实现的原因,因为如果我想要一个参数被忽略,我不会添加它然后将它的值设置为null。 我要么不首先添加它,要么我将从SqlParameterCollection中删除它。 如果我添加一个参数,并设置它的值(即使设置为null),我希望它在查询中被使用,我希望null表示空值。

我听说他们并没有因为性能原因而以“正确”的方式实现它,但这很荒谬,正如所示,因为调用SqlParameterCollection.AddWithValue方法无论如何都会将所有内容转换为对象,并将没有值的Nullable实例转换为null对象是C#语言的一个固有部分,根本不是性能打击。 微软应该解决这个问题。