首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Oracle返回某个数字(4)列的十进制

Oracle返回某个数字(4)列的十进制
EN

Stack Overflow用户
提问于 2014-06-03 19:22:37
回答 1查看 3.8K关注 0票数 5

我正在使用ODP.NET执行一个查询,该查询从一个表中选择许多列,包括几个数字(4)列。

当对本地dev 10.2实例执行查询时,所有数字(4)列都作为Int16实例返回。这是可以的,也是预料之中的。

当对另一个11.2实例执行查询时,除了最后一个数字(4)列之外,所有列都是Int16的实例,但最后一个是十进制的实例,它目前正在破坏我的代码。我可以在我的申请中解决这个问题,但它的任意性正在扼杀我。这怎么可能呢?这有可能吗? --我的意思是,它是同一个查询,相同的表,所有列都是相同类型的,但是其中一个在数据读取器中得到了不同的C#类型。怎么会发生这种事?

编辑->,我正在运行测试。即使我只从单个表中选择了单个列,没有连接、联合或位置或任何东西,问题也会发生。尝试删除列并重新创建它;同样的问题。尝试使用相同的列创建表的副本,问题不断发生。尝试创建一个列较少的表副本,问题停止发生。这是否可能仅仅是因为表中行为不当的列的数量/位置?(表有77列,有问题的列是表中的最后一列)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-10 01:29:16

是的,我们遇到了同样的问题--即使对于没有十进制分数的值,ODP.NET也用OracleDecimal替换输出数字声明。

在我看来,如果类型被声明为仅仅是数字,或者被oracle查询解释成十进制,那么即使值没有分数,它也会变成十进制。这与数字(N,0)定义不同,其中ODP.NET实际上根据数字数计算出.NET类型,并选择最小的有符号整数或浮点数/十进制类型来表示。

如果您提供了实际的代码示例,它会有所帮助,但是对于任何ExecuteDataReader()调用,下面的代码应该是安全的:

代码语言:javascript
复制
  using(var reader = cmd.ExecuteReader())
  {
    while(reader.Read())
    {
      var v = Convert.ToInt16(reader["name"]);
    }
  }

由于OracleDecimal没有实现IConvertible,并且没有使用Convert.ToInt32()调用转换为Int32或类似类型(异常时失败),因此输出参数的问题会变得更糟。

问题是OracleDataReader.GetInt16()的实现如下:

代码语言:javascript
复制
  int num2 = (int) this.m_pOpoMetValCtx->pColMetaVal[i].Scale;
  int num3 = (int) this.m_pOpoMetValCtx->pColMetaVal[i].Precision;
  if (num2 > 0 || num3 - num2 >= 5)
    throw new InvalidCastException();

所以它可能仍然会失败,但至少你会知道,由于一些未知的原因,这个规模是肯定的。这种模式在多个地方重复,通常所有的数字类型都在内部用ODP.NET表示为OracleDecimal,然后根据比例和精度将其映射到Int16、Int32、Int64、Float、Double和Decimal。

所以对于下面的查询

代码语言:javascript
复制
  SELECT CAST(1 AS NUMBER(3,0)) as c1, CAST(220 AS NUMBER) as c2 FROM DUAL

以下工作:

代码语言:javascript
复制
  var v = Convert.ToInt16(reader["c2"]);

而以下操作失败:

代码语言:javascript
复制
  var v = reader.GetInt16(1); // InvalidCastException

我发现的另一个解决方法是在定义输出或返回参数时,使用OracleDbTypeEx帮助。

例如,如果oracle输出参数创建为

代码语言:javascript
复制
  var p = new OracleParameter("name",OracleDbType.Int32, ParameterDirection.Output)

它以OracleDecimal的形式返回,并导致前面描述的问题,但当声明如下:

代码语言:javascript
复制
  var p = new OracleParameter("name",OracleDbType.Int32, ParameterDirection.Output);
  p.OracleDbCodeEx = OracleDbType.Int32;

它工作得很好,值类型实际上是.net类型和System.Int32类型。

总的来说,ODP.NET实现非常糟糕,包括方法重载方面的一些选择。在另一个例子中,OracleDataReader.GetOrdinal()被实现为列名称的循环。这个库的用户非常小心,并且特别注意功能测试。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24023318

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档