将空值分配给SqlParameter


188

下面的代码给出了一个错误-“没有从DBnull到int的隐式转换”。

SqlParameter[] parameters = new SqlParameter[1];    
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex;
parameters[0] = planIndexParameter;

4
您需要将AgeItem.AgeIndex转换为我认为的对象... stackoverflow.com/questions/202271/… (顺便说一句,为什么==在第三行的末尾?)
Greg 2010年

Answers:


341

问题在于?:操作员无法确定返回类型,因为您正在返回int不兼容的值或DBNull类型值。

您当然可以将AgeIndex的实例转换为object可以满足?:要求的类型。

您可以??按以下方式使用null-coalescing运算符

SqlParameter[] parameters = new SqlParameter[1];     
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
planIndexParameter.Value = (object)AgeItem.AgeIndex ?? DBNull.Value;
parameters[0] = planIndexParameter; 

这是MSDN文档中用于?:操作员的引言,解释了该问题。

first_expression和second_expression的类型必须相同,或者必须存在从一种类型到另一种类型的隐式转换。


尝试将null强制转换为object时,为什么没有引发异常?我认为应该是AgeItem.AgeIndex as object
Niels Brinch 2012年

@Niels Brinch,不会有例外,因为null是一个对象,只要您不尝试取消引用它,就完全合法。但是,在此示例中,它不是null强制转换为对象,而是DBNull.Value实际上是一种值类型。?? 运算符说“如果AgetItem.AgeIndex为null,则返回DBNull.Value,否则返回AgeItem.AgeIndex”,然后将响应转换为对象。有关更多详细信息,请参见空合并运算符。msdn.microsoft.com/en-us/library/ms173224.aspx
克里斯·泰勒

3
从技术上讲,使用null-coalescing运算符??的解决方案与使用常规三进制的解决方案相同?:-您仍然需要强制AgeItem.AgeIndex转换为对象:planIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;
newfurniturey

如果要使用正则三元?:进行特定于类型的比较,则强制转换整个表达式将不起作用。你要投非的DBNull参数,如下所示:someID == 0 ? DBNull.Value : (object)someID
ingredient_15939

的确是这样,但是如果您需要使用可为空的值作为导致使用SqlParameter的函数的入口参数,并且如果为空,则说明这种方法不起作用,您应该使用简单的If-Else方法。例如:sample.Text.Trim()!=“”?func(sample.Text):DBNull.Value; 不能作为?:和??
QMaster 2015年

102

可接受的答案建议使用演员表。但是,大多数SQL类型都有一个特殊的Null字段,可用于避免这种转换。

例如,SqlInt32.Null“表示可以分配给SqlInt32类的该实例的DBNull。”

int? example = null;
object exampleCast = (object) example ?? DBNull.Value;
object exampleNoCast = example ?? SqlInt32.Null;

2
该建议看起来很有希望,所以我尝试了“ System.Data.SqlTypes.SqlString.Null”,但是它不起作用。它将实际的字符串“ Null”(“ N”,“ u”,“ l”,“ l”)放入字段中,而不是将其保留为空白(为true)。但是,使用与(object)强制转换的旧版2010年“可接受的答案”?DBNull.Value正常工作。(我使用的ADO.NET提供程序是SQLite,但我不确定这是否有所不同。)我建议其他人仔细测试Brian的技巧,以确保null行为按预期工作。
JasDev 2015年

6
@JasDev:我隐约记得在对高级用户(我认为是Marc Gravell)的评论中描述了这个技巧,并被告知仅适用于Microsoft SQL Server。
布赖恩

@JasDev提供程序将成为Brain Point指出的在SQL Server中工作的区别。
Lankymart

此答案仅将对对象的显式强制转换替换为hidden.one。在示例代码中,exampleNoCast已声明为object,因此仍会强制转换为object。如果像在OP的代码中一样,将值直接分配给也是对象类型的SqlParameter.Value,那么您仍然可以进行强制转换。
斯科特(Scott)

31

DBNull.Value除非在存储过程中指定了默认值(如果使用存储过程),则需要在SQLCommand中作为空参数传递。最好的方法是DBNull.Value在执行查询之前为所有缺少的参数分配值,然后在foreach之后执行此操作。

foreach (SqlParameter parameter in sqlCmd.Parameters)
{
    if (parameter.Value == null)
    {
        parameter.Value = DBNull.Value;
    }
}

否则,请更改此行:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex;

如下:

if (AgeItem.AgeIndex== null)
    planIndexParameter.Value = DBNull.Value;
else
    planIndexParameter.Value = AgeItem.AgeIndex;

因为您不能在条件语句中使用不同类型的值,因为DBNull和int彼此不同。希望这会有所帮助。


这个答案非常好,因为它以各种方式举例说明。我喜欢第一种方法,我通常使用EF,但由于此要求无法实现,因此为我节省了很多时间。谢谢!
Leandro

23

使用一行代码,请尝试以下操作:

var piParameter = new SqlParameter("@AgeIndex", AgeItem.AgeIndex ?? (object)DBNull.Value);

5

试试这个:

SqlParameter[] parameters = new SqlParameter[1];    
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);

planIndexParameter.IsNullable = true; // Add this line

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex== ;
parameters[0] = planIndexParameter;

5

如果使用条件(三元)运算符,则编译器需要在这两种类型之间进行隐式转换,否则会出现异常。

因此,您可以通过将以下两者之一转换为System.Object

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : (object) AgeItem.AgeIndex;

但是由于结果不是很漂亮,并且您始终必须记住这种转换,因此可以改用以下扩展方法:

public static object GetDBNullOrValue<T>(this T val)
{
    bool isDbNull = true;
    Type t = typeof(T);

    if (Nullable.GetUnderlyingType(t) != null)
        isDbNull = EqualityComparer<T>.Default.Equals(default(T), val);
    else if (t.IsValueType)
        isDbNull = false;
    else
        isDbNull = val == null;

    return isDbNull ? DBNull.Value : (object) val;
}

然后,您可以使用以下简洁代码:

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue();

1

我认为更好的方法是使用SqlCommand类的Parameters属性来执行此操作:

public static void AddCommandParameter(SqlCommand myCommand)
{
    myCommand.Parameters.AddWithValue(
        "@AgeIndex",
        (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex);
}

但是,如果值为DBNull.Value,则ADO.NET可能很难猜测可能是什么SqlDbType .....这很方便-但有点危险....
marc_s 2010年

1

考虑使用可用的Nullable(T)结构。它仅允许您设置具有值的值,并且SQL Command对象将识别可为空的值并相应地进行处理,而不会麻烦。


1
if (_id_categoria_padre > 0)
{
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre;
}
else
{
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value;
}

0

试试这个:

if (AgeItem.AgeIndex != null)
{
   SqlParameter[] parameters = new SqlParameter[1];
   SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
   planIndexParameter.Value = AgeItem.AgeIndex;
   parameters[0] = planIndexParameter;
}

换句话说,如果参数为null,则不要将其发送到您的存储过程(当然,假设存储的proc接受您的问题中隐含的空参数)。


但是现在,您只是省略了一个参数-我高度怀疑存储过程对此是否满意...。最有可能的是,该调用将失败,指出“所提供的@AgeIndex参数没有值”。 。
marc_s

哇。苛刻。如果未传递参数(@AgeIndex int = 0),只需将存储的proc写入默认值即可。一直发生。客户端可以接受默认值,也可以通过传递参数来覆盖它。为什么要下票?
Flipster,2011年

0

尝试这样的事情:

if (_id_categoria_padre > 0)
{
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre;
}
else
{
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value;
}

0
int? nullableValue = null;
object nullableValueDB
{
   get{
       if(nullableValue==null)
          return DBNull.Value;
       else
          return (int)nullableValue;
   }
}

我正在这样解决。


0
if (AgeItem.AgeIndex== null)  
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = DBNull);  
else  
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = AgeItem.AgeIndex);

0

这就是我要做的...

        var PhoneParam = new SqlParameter("@Phone", DBNull.Value);
        if (user.User_Info_Phone != null)
        {
            PhoneParam.SqlValue = user.User_Info_Phone;
        }

        return this.Database.SqlQuery<CustLogonDM>("UpdateUserInfo @UserName, @NameLast, @NameMiddle, @NameFirst, @Address, @City, @State, @PostalCode, @Phone",
            UserNameParam, NameLastParam, NameMiddleParam, NameFirstParam, AddressParam, CityParam, StateParam, PostalParam, PhoneParam).Single();

0
            dynamic psd = DBNull.Value;

            if (schedule.pushScheduleDate > DateTime.MinValue)
            {
                psd = schedule.pushScheduleDate;
            }


            sql.DBController.RunGeneralStoredProcedureNonQuery("SchedulePush",
                     new string[] { "@PushScheduleDate"},
                     new object[] { psd }, 10, "PushCenter");

0

一个简单的扩展方法是:

    public static void AddParameter(this SqlCommand sqlCommand, string parameterName, 
        SqlDbType sqlDbType, object item)
    {
        sqlCommand.Parameters.Add(parameterName, sqlDbType).Value = item ?? DBNull.Value;
    }

0

我使用带有空检查的简单方法。

    public SqlParameter GetNullableParameter(string parameterName, object value)
    {
        if (value != null)
        {
            return new SqlParameter(parameterName, value);
        }
        else
        {
            return new SqlParameter(parameterName, DBNull.Value);
        }
    }

1
这是条件逻辑倒退吗?DBNull.Value应该在第一个中吗?
Mark Schultheiss,

当然是。固定。谢谢。
Zhi An

0

我的代码,在实际项目中工作在使sqlparameter之前,请先查看三元运算符,这对我来说是最好的方法,没有问题:

    public bool Key_AddExisting
    (
          string clave
        , int? idHito_FileServer
        , int? idTipoDocumental_Almacen
        , string tipoExp_CHJ
        , int idTipoExp_Verti2
        , int idMov_Verti2
    )
    {
        List<SqlParameter> pars = new List<SqlParameter>()
        {
              new SqlParameter { ParameterName = "@Clave", Value = clave }
    LOOK -> , idHito_FileServer == null ? new SqlParameter { ParameterName = "@IdHito_FileServer", Value = DBNull.Value } : new SqlParameter { ParameterName = "@IdHito_FileServer", Value = idHito_FileServer }
    LOOK -> , idTipoDocumental_Almacen == null ? new SqlParameter { ParameterName = "@IdTipoDocumental_Almacen", Value = DBNull.Value } : new SqlParameter { ParameterName = "@IdTipoDocumental_Almacen", Value = idTipoDocumental_Almacen }
            , new SqlParameter { ParameterName = "@TipoExp_CHJ", Value = tipoExp_CHJ }
            , new SqlParameter { ParameterName = "@IdTipoExp_Verti2", Value = idTipoExp_Verti2 }
            , new SqlParameter { ParameterName = "@IdMov_Verti2", Value = idMov_Verti2 }
        };

        string sql = "INSERT INTO [dbo].[Enlaces_ClavesCHJ_MovimientosVerti2] " +
            "( " +
            "  [Clave] " +
            ", [IdHito_FileServer] " +
            ", [IdTipoDocumental_Almacen] " +
            ", [TipoExp_CHJ] " +
            ", [IdTipoExp_Verti2] " +
            ", [IdMov_Verti2] " +
            ") " +
            "VALUES" +
            "( " +
            "  @Clave" +
            ", @IdHito_FileServer" +
            ", @IdTipoDocumental_Almacen" +
            ", @TipoExp_CHJ" +
            ", @IdTipoExp_Verti2" +
            ", @IdMov_Verti2" +
            ")";

        return DbBasic.ExecNonQuery(ref this.conn, sql, pars);
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.