Как использовать Dapper micro-ORM с Oracle для сопоставления NUMBER (OracleDecimal)

Поставщик ODP.NET вызывает исключение в IDataReader.GetValue()/GetValues ​​(), если тип столбца - NUMBER(x,y), так что он переполняет все числовые типы.NET. Таким образом, Dapper не может сопоставить такой столбец со свойством POCO.

У меня есть хранимая процедура Oracle, которая использует выходной параметр REF CURSOR для возврата записей с 3 столбцами. По сути, все 3 являются NUMBER (что-то), но, похоже, управляемый поставщик ODP.NET Oracle решает, в какой тип ODP.NET или.NET их превратить.

У меня были проблемы с отображением записей Dapper Query() из этого спрока в 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 и использование ванильного 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

То, что я немного просмотрел и остановил в файле Daq SqlMapper.cs, показывает мне, что он извлекает данные из читателя с помощью GetValue () / GetValues ​​(), как указано выше, что не удается.

Любые предложения, как исправить Dapper вверх? Большое спасибо.

ОБНОВИТЬ:

После размышления я RTFMed: Раздел 3, "Получение данных из объекта OracleDataReader" в Oracle Data Provider for .NET Developer Guide, который объясняет. Для столбцов NUMBER OracleDataReader в ODP.NET попытается использовать последовательность типов.NET от байтов до десятичных, чтобы предотвратить переполнение. Но NUMBER может по-прежнему переполнять десятичное число, давая недопустимое исключение приведения, если вы пытаетесь использовать любой из методов доступа.NET читателя (GetValue()/GetValues ​​()), и в этом случае вам нужно использовать метод доступа типа ODP.NET читателя GetProviderSpecificValue(), который дает вам OracleDecimal, и если он переполняет десятичное число, его свойство Value выдаст вам исключение переполнения, и единственным выходом для вас является принудительное приведение его к меньшему типу с помощью одного из методов OracleDecimal ToXxx().

Но, конечно, средство доступа к типу ODP.NET не является частью интерфейса IDataReader, используемого Dapper для хранения объектов чтения, поэтому кажется, что Dapper сам по себе несовместим с Oracle, когда тип столбца переполняет все типы.NET.

Остается вопрос - умные люди знают, как расширить Dapper, чтобы справиться с этим. Мне кажется, мне нужна точка расширения, где я мог бы обеспечить реализацию того, как использовать читателя (заставляя его использовать GetDouble() вместо GetValue(), или приводя к OracleDataReader и вызывая GetProviderSpecificValue()) для определенного свойства POCO или типы столбцов.

1 ответ

Чтобы избежать этой проблемы, я использовал:

CAST(COLUMN AS BINARY_DOUBLE)

или жеTO_BINARY_DOUBLE(COLUMN)

В перечисленных здесь типах Oracle это описывается так:

64-битное число с плавающей запятой. Этот тип данных требует 9 байтов, включая длину байта.

Большинство других типов чисел, используемых Oracle, имеют максимальный размер 22 байта, так что это так же хорошо, как и для.NET

Другие вопросы по тегам