具有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#语言的一个固有部分,根本不是性能打击。 微软应该解决这个问题。