如何使用Dapper micro-ORM与Oracle映射NUMBER(OracleDecimal)

时间:2014-09-30 22:15:47

标签: dapper odp.net-managed

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

我有一个Oracle存储过程,它使用REF CURSOR输出参数来返回3列记录。从根本上说,所有3个都是NUMBER(某事),但是ODP.NET Oracle managed provider似乎决定将它们变成什么样的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()从阅读器中提取数据,如上所述,它失败了。 / p>

有关如何修补Dapper的任何建议吗?非常感谢。

更新:

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

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

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

1 个答案:

答案 0 :(得分:0)

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

CAST(COLUMN AS BINARY_DOUBLE)

TO_BINARY_DOUBLE(COLUMN)

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

  

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

Oracle使用的大多数其他数字类型最多为22个字节,因此这与.NET相同[/ p>]