【问题标题】:Convert OracleParameter.Value to Int32将 OracleParameter.Value 转换为 Int32
【发布时间】:2011-03-02 20:19:51
【问题描述】:

我有一个这样的存储过程调用:

using (OracleConnection con = new OracleConnection(ConfigurationManager.AppSettings["Database"]))
using (OracleCommand cmd = new OracleCommand("Package.Procedure", con))
{
   Int32 existsCount;

   cmd.CommandType = CommandType.StoredProcedure;
   cmd.Parameters.Add("successCount", OracleDbType.Int32, 0, ParameterDirection.InputOutput);
   cmd.Parameters.Add("BusinessId", OracleDbType.Int64, listRec.BusinessId, ParameterDirection.Input);

    con.Open();
    cmd.ExecuteScalar();
    con.Close();

    existsCount = Convert.ToInt32(cmd.Parameters["successCount"].Value);

    return (existsCount);
}

但是在这一行:

existsCount = Convert.ToInt32(cmd.Parameters["successCount"].Value);

它抛出异常“无法将 'Oracle.DataAccess.Types.OracleDecimal' 类型的对象转换为 'System.IConvertible' 类型。”

有什么想法吗?谢谢。

【问题讨论】:

    标签: c# oracle casting


    【解决方案1】:

    就我而言,我在 Oracle 中使用 Bulk Insert,遇到了同样的错误,让我在这里分享我的解决方案。我通过添加解决了它

    oracleCommand.ArrayBindCount = datas.Count; 
    

    那是我忘了设置ArrayBindCount 属性。

    【讨论】:

      【解决方案2】:

      我不知道运行时的返回类型,因为执行代码在一个正在开发的跨平台数据访问框架内,所以我在参数值类型上使用了一个开关来访问底层的 Oracle[type].Value 属性用于各种 Oracle 托管数据访问类型。

      public override object GetValue(IDataParameter parameter)
      {
          if (parameter == null)
          {
              throw new ArgumentNullException(nameof(parameter));
          }
      
          // https://docs.oracle.com/cd/B19306_01/win.102/b14307/OracleDbTypeEnumerationType.htm
          if (parameter is OracleParameter)
          {
              switch (parameter.Value)
              {
                  case OracleBinary oracleBinary:
                      // returns byte[]
                      return oracleBinary.Value;
                  case OracleBoolean oracleBoolean:
                      // returns bool
                      return oracleBoolean.Value;
                  case OracleDate oracleDate:
                      // returns DateTime
                      return oracleDate.Value;
                  case OracleDecimal oracleDecimal:
                      // oracleDecimal.Value is Decimal, so we convert to correct type.
                      return parameter.DbType == DbType.Decimal
                          ? oracleDecimal.Value
                          : Convert.ChangeType(oracleDecimal.Value, parameter.DbType.ToType());
                  case OracleIntervalDS oracleIntervalDS:
                      // returns TimeSpan
                      return oracleIntervalDS.Value;
                  case OracleIntervalYM oracleIntervalYM:
                      // returns Long
                      return oracleIntervalYM.Value;
                  case OracleTimeStamp oracleTimeStamp:
                      // returns DateTime
                      return oracleTimeStamp.Value;
                  case OracleTimeStampLTZ oracleTimeStampLTZ:
                      // returns DateTime
                      return oracleTimeStampLTZ.Value;
                  case OracleTimeStampTZ oracleTimeStampTZ:
                      // returns DateTime
                      return oracleTimeStampTZ.Value;
                  default:
                      throw new NotSupportedException(
                          parameter.Value != null
                              ? parameter.Value.GetType().Name
                              : parameter.ParameterName);
              }
          }
          else
          {
              throw new NotSupportedException(parameter.GetType().Name);
          }
      }
      

      【讨论】:

      • 如果 Oracle 提供对 Value 属性的底层本机类型的隐式转换会很好。
      【解决方案3】:

      使用起来更高效

      Convert.ToInt32((decimal)(OracleDecimal)(cmd.Parameters["successCount"].Value))
      

      【讨论】:

        【解决方案4】:

        我建议你转换成String,然后你再从String转换成Integer。

        Dim tmpIdSesiónCalificación As String = 
            parametroIdSesiónCalificación.Value.ToString
        _idSesiónCalificación = Convert.ToInt32(tmpIdSesiónCalificación)
        

        【讨论】:

          【解决方案5】:

          你也可以试试:

          Oracle.DataAccess.Types.OracleDecimal d = (Oracle.DataAccess.Types.OracleDecimal)cmd.Parameters["successCount"].Value;
          
          if( d.IsNull )
              existsCount = 0;
          else
              existsCount = d.ToInt32( );
          

          【讨论】:

          • 我已经对此进行了测试,它的性能比以前的解决方案更好。
          • 这是最正确的答案——不知道为什么一直在底部。
          • 检查 null 是个好主意,但我忘了做。
          【解决方案6】:

          怎么样

          existsCount = int.Parse(cmd.Parameters["successCount"].Value.ToString());
          

          【讨论】:

          • 这并不愚蠢。如果有的话,Convert.To... 应该是更好的选择。由于 int.Parse() 基本上只是解析字符串值,这应该会增加一些开销。但是,也可能起作用的一件事(一开始没有考虑过)是:existsCount = (int)cmd.Parameters["successCount"].Value 如果 Oracle lib 提供了显式转换。
          • 为什么选择 TryParse?如果可以解析 OracleDecimal 应该没问题。如果返回值超出 int32 范围,则抛出异常总比默默地忽略这一事实要好。在这种特殊情况下 int.Parse() 更好(只是我的意见)。
          • 将数字类型转换为字符串只是为了将其转换回数字是错误的。
          • @GregZ。确实如此。 Oracle.DataAccess.Types.OracleDecimal 应该首先实现 IConvertible,所以 Convert.ToInt32(...) 会成功,但这可以完成工作。但是@Brads 解决方案Convert.ToInt32((decimal)(OracleDecimal)(cmd.Parameters["successCount"].Value)) 更好(但为时已晚:-)
          • @MarkLauter 需要解释一下吗? Convert.ToInt32 有一个 Convert.ToInt32(object value) 重载 value: An object that implements the System.IConvertible interface 换句话说:如果类型本身正确实现 IConvertible,您不必在设计时知道类型,如果您不知道类型在设计时间。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-27
          • 2015-03-14
          • 2022-01-02
          • 1970-01-01
          相关资源
          最近更新 更多