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

Pat*_*ins 22 .net c# sql-server nullable

我有一个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);
Run Code Online (Sandbox Code Playgroud)

我尝试将生日的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);
Run Code Online (Sandbox Code Playgroud)

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

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

任何的想法?

Dav*_*d M 57

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

dbParam_au_id.Value = (object)birthday ?? DBNull.Value;
Run Code Online (Sandbox Code Playgroud)


Tri*_*nko 15

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

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

#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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • 一组不错的实用函数。如果您使用 3.5 或更高版本,您可以将这些调整为 SqlParameterCollection 的扩展,并且您将拥有 command.Paramters.AddParameter(...) 经验 (2认同)