【问题标题】:Assign null to a SqlParameter将 null 分配给 SqlParameter
【发布时间】:2011-06-01 03:41:16
【问题描述】:

下面的代码给出了一个错误——“没有从 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;

【问题讨论】:

标签: c# dbnull sqlparameter


【解决方案1】:

问题在于?: 运算符无法确定返回类型,因为您返回的要么是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 documentation?: 运算符的引用,用于解释问题

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

【讨论】:

  • 为什么尝试将null转换为对象时没有抛出异常?我认为应该是AgeItem.AgeIndex as object
  • @Niels Brinch,不会有例外,因为 null 是一个对象,只要您不尝试取消引用它,它就是完全合法的。然而,在这个例子中,它不是 null 被强制转换为对象,它是 DBNull.Value,它实际上是一个值类型。这 ??运算符说“如果 AgetItem.AgeIndex 为空,则返回 DBNull.Value,否则返回 AgeItem.AgeIndex”,然后将响应转换为对象。有关更多详细信息,请参阅空合并运算符。 msdn.microsoft.com/en-us/library/ms173224.aspx
  • 从技术上讲,使用空合并运算符 ?? 的解决方案与使用常规三元 ?: 的解决方案相同 - 您仍然需要将 AgeItem.AgeIndex 强制转换为对象: planIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;.
  • 如果您要使用正则三元组?: 进行特定类型的比较,那么强制转换整个表达式将不起作用。您必须像这样强制转换非 dbnull 参数:someID == 0 ? DBNull.Value : (object)someID
  • 这是真的,但是如果您需要使用可为空的值作为函数的入口参数,结果会消耗 SqlParameter,如果它为 null,则您遇到错误,这种方式是行不通的,您应该只使用简单的 If-Else 方式。例如: sample.Text.Trim() != "" ? func(sample.Text) : DBNull.Value;不能作为 ?: 和 ??
【解决方案2】:

The accepted answer 建议使用演员表。但是,大多数 SQL 类型都有一个特殊的 Null 字段,可以用来避免这种强制转换。

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

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

【讨论】:

  • 这个建议看起来很有希望,所以我尝试了“System.Data.SqlTypes.SqlString.Null”,但它不起作用。它将“Null”('N'、'u'、'l'、'l')的实际字符串放入字段中,而不是将其留空并保留为 true(null)。但是,旧的 2010 年“接受的答案”使用 cast with (object) ?? DBNull.Value 工作正常。 (我使用的 ADO.NET 提供程序是 SQLite,但我不确定这是否会有所不同。)我建议其他人仔细测试 Brian 的提示,以确保 null 行为按预期工作。
  • @JasDev:我隐约记得在对一位高级用户(我认为是 Marc Gravell)的评论中描述了这个技巧,并被告知它只适用于 Microsoft SQL Server。
  • @JasDev 提供者将是它在 SQL Server 中的不同之处,因为 Brain point 已经出来了。
  • 此答案仅用implicit.one 替换了对对象的显式强制转换。在示例代码中,exampleNoCast 被声明为对象,因此仍会发生强制转换为对象。如果像在 OP 的代码中一样,将值直接分配给也是对象类型的 SqlParameter.Value,那么您仍然会得到强制转换。
  • 即使在 SQL Server 上,使用 DataTable/SqlBulkCopy 时似乎也会失败。
【解决方案3】:

您需要在 SQLCommand 中将 DBNull.Value 作为空参数传递,除非在存储过程中指定了默认值(如果您正在使用存储过程)。最好的方法是在查询执行之前为任何缺少的参数分配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,但在这个要求中无法做到,它为我节省了很多时间。谢谢!
  • foreach 循环对我来说非常有用!谢谢
【解决方案4】:

用一行代码,试试这个:

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

【讨论】:

  • 您也可以将AgeItem.AgeIndex 转换为对象:(object)AgeItem.AgeIndex。但是,是的,也更喜欢你的方法
【解决方案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;

【讨论】:

    【解决方案6】:

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

    因此,您可以通过将两者之一转换为 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();
    

    【讨论】:

      【解决方案7】:

      在我看来,更好的方法是使用 SqlCommand 类的 Parameters 属性:

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

      【讨论】:

      • 但是如果值是DBNull.Value,ADO.NET 可能有点难以猜测可能是什么 SqlDbType ......这很方便 - 但有点危险。 ...
      【解决方案8】:

      试试这个:

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

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

      【讨论】:

      • 但是现在,您只是省略了一个参数 - 我非常怀疑存储过程会不会对此感到满意.... 很可能,调用将失败,并指出“没有提供参数 @AgeIndex 的值这是预期的”.....
      • 哇。残酷的。如果未传递参数(@AgeIndex int = 0),只需将存储的过程写入默认值即可。无时无刻不在发生。客户端可以接受默认值,也可以通过传递参数来覆盖它。为什么投反对票?
      【解决方案9】:

      考虑使用可用的 Nullable(T) 结构。它只会让你设置值,如果你有它们,你的 SQL Command 对象将识别可以为空的值并相应地处理,而你不会有任何麻烦。

      【讨论】:

        【解决方案10】:
        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;
        }
        

        【讨论】:

          【解决方案11】:

          一个简单的扩展方法是:

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

          【讨论】:

            【解决方案12】:

            我使用一个简单的方法来检查空值。

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

            【讨论】:

            • 那是条件逻辑倒退吗? DBNull.Value 应该在第一个吗?
            • 当然是。固定的。谢谢。
            【解决方案13】:

            我的代码,在实际项目中工作 在制作sql参数之前查看三元运算符 这对我来说是最好的方式,没有问题:

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

            【讨论】:

              【解决方案14】:

              试试这样的:

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

              【讨论】:

                【解决方案15】:
                int? nullableValue = null;
                object nullableValueDB
                {
                   get{
                       if(nullableValue==null)
                          return DBNull.Value;
                       else
                          return (int)nullableValue;
                   }
                }
                

                我就是这样解决的。

                【讨论】:

                  【解决方案16】:
                  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);
                  

                  【讨论】:

                    【解决方案17】:

                    这就是我所做的......

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

                    【讨论】:

                      【解决方案18】:
                                  dynamic psd = DBNull.Value;
                      
                                  if (schedule.pushScheduleDate > DateTime.MinValue)
                                  {
                                      psd = schedule.pushScheduleDate;
                                  }
                      
                      
                                  sql.DBController.RunGeneralStoredProcedureNonQuery("SchedulePush",
                                           new string[] { "@PushScheduleDate"},
                                           new object[] { psd }, 10, "PushCenter");
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2012-07-21
                        • 1970-01-01
                        • 2017-08-27
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多