5

如果列类型为 NUMBER(x,y),ODP.NET 提供程序会在 IDataReader.GetValue()/GetValues() 中引发异常,这样它将溢出所有 .NET 数字类型。所以 Dapper 无法将这样的列映射到 POCO 属性。

我有一个使用 REF CURSOR 输出参数返回 3 列记录的 Oracle 存储过程。基本上所有 3 都是 NUMBER(一些东西),但ODP.NET Oracle 托管提供程序似乎决定将它们变成什么 ODP.NET 或 .NET 类型。

我一直在使用 Dapper 的 Query() 将记录从这个 sproc 映射到 POCO 时遇到问题。也许这实际上不是我的错,这一次——似乎当一列作为 ODP.NET 类型而不是 .NET 类型出现时,Dapper 失败了。如果我从我的 POCO 中评论一个有问题的专栏,一切正常。

这里有一对行来说明:

--------------------------------------------------------------------
RDWY_LINK_ID           RLC_LINK_OSET          SIGN                   
---------------------- ---------------------- ---------------------- 
1829                   1.51639964279667746989761971196153763602 1 
14380                  578.483600357203322530102380288038462364 -1 

第一列在 .NET 中被视为int,第二列为OracleDecimal类型,第三列为十进制。第二个是问题。

例如,暂时删除 Dapper 并使用 vanilla ODP.NET 访问这些记录就表明了问题:

int linkid = (int)reader.GetValue(0);
decimal linksign = (decimal)reader.GetValue(2);
//decimal dlinkoffset = (decimal)reader.GetValue(1); //**invalid cast exception at at Oracle.ManagedDataAccess.Client.OracleDataReader.GetDecimal(Int32 i)**
//object olinkoffset = reader.GetValue(1); //**same**
//decimal dlinkoffset = reader.GetDecimal(1); //**same**
//object[] values = new object[reader.FieldCount];
//reader.GetValues(values); //**same**
OracleDecimal linkoffset = (OracleDecimal)reader.GetProviderSpecificValue(1); //this works!
double dblinkoffset = reader.GetDouble(1); //interesting, this works too!
//decimal dlinkoffset = linkoffset.Value; //overflow exception
dblinkoffset = linkoffset.ToDouble(); //voila

我在 Dapper 的 SqlMapper.cs 文件中所做的少量浏览和断点显示它正在使用 GetValue()/GetValues() 从读取器中提取数据,如上所述,但失败了。

有什么建议可以修补 Dapper 吗?非常感谢。

更新:

经过反思,我在 RTFMed: Oracle Data Provider for .NET Developer's Guide 的第 3 节“从 OracleDataReader 对象中获取数据”进行了解释。对于 NUMBER 列,ODP.NET 的 OracleDataReader 将尝试从 Byte 到 Decimal 的一系列 .NET 类型以防止溢出。但是 NUMBER 仍可能会溢出 Decimal,如果您尝试任何阅读器的 .NET 类型访问器 (GetValue()/GetValues()),则会给出无效的强制转换异常,在这种情况下,您必须使用阅读器的 ODP.NET 类型访问器 GetProviderSpecificValue( ),它给你一个 OracleDecimal,如果它溢出一个 Decimal,它的 Value 属性会给你一个溢出异常,你唯一的办法是使用 OracleDecimal 的 ToXxx() 方法之一将它强制转换为较小的类型。

但是,ODP.NET 类型访问器当然不是 Dapper 用来保存读取器对象的 IDataReader 接口的一部分,因此当列类型溢出所有 .NET 类型时,Dapper 本身似乎与 Oracle 不兼容。

问题仍然存在 - 聪明人知道如何扩展 Dapper 来处理这个问题。在我看来,我需要一个扩展点,我可以提供有关如何使用阅读器的实现(强制它使用 GetDouble() 而不是 GetValue(),或强制转换为 OracleDataReader 并为某些 POCO 属性调用 GetProviderSpecificValue())或列类型。

4

1 回答 1

1

为了避免这个问题,我使用了:

CAST(COLUMN AS BINARY_DOUBLE)

或者 TO_BINARY_DOUBLE(COLUMN)

在此处列出的 Oracle 类型中,它被描述为:

64 位浮点数。此数据类型需要 9 个字节,包括长度字节。

Oracle 使用的大多数其他数字类型最大为 22 字节,因此这与 .NET 一样好

于 2016-09-13T18:03:01.093 回答