【问题标题】:SqlParameter with Nullable value give error while ExecuteNonQuery?具有 Nullable 值的 SqlParameter 在 ExecuteNonQuery 时给出错误?
【发布时间】:2009-05-14 13:32:54
【问题描述】:

我有一个 sql 查询,它的参数在数据库 (Sql Server) 中可以为空。更新方法工作正常,直到用户在字段中输入一个空白,这会为 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'

有什么想法吗?

【问题讨论】:

  • 附带说明,我强烈建议您不要设置 DbType 属性,除非您将其用作输出参数。我从未见过无数由它引起的微妙错误,而且没有一个通过使用它来解决。

标签: c# .net sql-server nullable


【解决方案1】:

类型不兼容。试试这样的:

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

【讨论】:

    【解决方案2】:

    如果第一次正确编写了 SqlParameter 类... C# 空值将作为 DBNull.Value 处理。这很直观,因此将 SqlParameter 值设置为 null 在功能上等同于将其从 SqlParameterCollection 中删除。

    要纠正这个荒谬的 API 设计错误,请创建您自己的 AddParameter 方法(带有重载),该方法接受一个 SqlParameterCollection、一个字符串(参数名称)和一个对象(参数值)。

    #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
    

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

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

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

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

    【讨论】:

    • 很好的实用函数集。如果您使用的是 3.5 或更高版本,则可以将这些调整为 SqlParameterCollection 的扩展,您将拥有 command.Paramters.AddParameter(...) 经验
    • 七年后,这仍然是SqlParameterCollection Add 方法的行为。你还在使用这个解决方案吗?只是想知道在此期间是否有更好的解决方案。我目前将 AddRange 与参数数组一起使用,因此我正在考虑必须遍历数组并在 null 时替换每个数组的值...
    • @Doug 又过了五年,用了几年。我添加了一个扩展方法,它添加了一个数组并将空值转换为 DBNull。 public static void AddRangeIncludingNullValues(this SqlParameterCollection parameters, SqlParameter[] sqlParametersToAdd) { for (int i = 0; i &lt; sqlParametersToAdd.Length; i++) { sqlParametersToAdd[i].Value = sqlParametersToAdd[i].Value ?? DBNull.Value; } parameters.AddRange(sqlParametersToAdd); }
    猜你喜欢
    • 1970-01-01
    • 2012-10-12
    • 2016-08-12
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-05
    相关资源
    最近更新 更多