2014-09-30 35 views
3

如果列類型爲NUMBER(x,y),則ODP.NET提供程序在IDataReader.GetValue()/ GetValues()中引發異常,會溢出所有.NET數字類型。所以Dapper無法將這樣的列映射到POCO屬性。如何使用Dapper micro-ORM與Oracle映射NUMBER(OracleDecimal)

我有一個使用REF CURSOR輸出參數返回3列記錄的Oracle存儲過程。基本上所有3個都是NUMBER(東西),但ODP.NET Oracle managed provider似乎決定了ODP.NET或.NET類型將它們變成什麼樣。

我一直在用Dapper的Query()映射記錄從這個sproc到POCOs的記錄問題。也許它實際上不是我的錯,有一次 - 似乎當一個列出現爲ODP.NET類型而不是.NET類型時,Dapper失敗了。如果我從我的POCO中評論一個違規的專欄,一切都會奏效。

這裏的一對行來說明:

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

的第一列在.NET視爲INT,第二列作爲OracleDecimal類型,和第三作爲十進制。第二個是問題。

例如,對於當下去除小巧玲瓏,用香草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 

我在小巧玲瓏的SqlMapper.cs做一點什麼瀏覽和設置斷點文件顯示我說它使用GetValue()/ GetValues()從讀取器中提取數據,如上所述,失敗。

任何建議如何打補丁?非常感謝。

UPDATE:

在反射,我RTFMed:第3節,這解釋了Oracle Data Provider for .NET Developer’s Guide的 「從OracleDataReader對象獲得數據」。對於NUMBER列,ODP.NET的OracleDataReader將嘗試一系列從字節到十進制的.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並調用GetProviderSpecificValue())來獲得某些POCO屬性或列類型。

+0

嗯,這是一樣好。我不認爲會有這樣做的好方法。基本上,提供者特定的類型不能轉換(安全)到.NET類型,因爲沒有足夠的精度可用。如果你的POCO類型爲'OracleDecimal',那麼這將會很好,但是如果'GetValue'方法實際返回一個該類型的值而不是拋出異常,這隻會以通用的方式工作。你會注意到'IDataReader'(這是Dapper在內部使用的,因爲這是ADO.NET通過'ExecuteReader()'公開的)甚至不具有*'GetProviderSpecificValue()'。 – Cameron 2014-09-30 22:28:19

+0

如果我們檢測到oracle,我們已經做了一些偷偷摸摸的事情。我可以*看看*這個,但是我的問題是測試它:我不是Oracle專家。但這不是微不足道的。 GetValue失敗令人非常沮喪。這基本上是Oracle在世界上堅守着兩根手指。 – 2014-10-02 13:04:51

+0

我知道這已經過了一年多了,但你是否碰巧找到了解決這個問題的方法?我唯一的其他考慮是修改Oracle庫來做一些工作... – Thnesko 2016-09-13 17:41:58

回答

0

爲了避免這個問題,我用:

CAST(COLUMN AS BINARY_DOUBLE)

TO_BINARY_DOUBLE(COLUMN)

在Oracle類型列出here它描述爲:

64位浮點數。該數據類型需要9個字節,包括長度字節。

大多數Oracle使用的其他類型的數量是22個字節最大,所以它得到了.NET