Comment utiliser Dapper micro-ORM avec Oracle pour mapper NUMBER (OracleDecimal)

dapper odp.net-managed

Question

Le fournisseur ODP.NET déclenche une exception dans IDataReader.GetValue () / GetValues ​​() si le type de colonne est NUMBER (x, y) de sorte qu'il débordera tous les types numériques .NET. Ainsi, Dapper est incapable de mapper une telle colonne sur une propriété POCO.

J'ai une procédure stockée Oracle qui utilise un paramètre de sortie REF CURSOR pour renvoyer des enregistrements de 3 colonnes. Fondamentalement, tous les 3 sont NUMBER (quelque chose), mais le fournisseur géré ODP.NET Oracle semble décider quel type ODP.NET ou .NET pour les transformer.

J'ai eu des problèmes avec les enregistrements de mappage de Dapper Query () de ce sproc dans les POCO. Peut-être que ce n'est pas de ma faute, pour une fois - il semble que lorsqu'une colonne apparaît comme un type ODP.NET au lieu d'un type .NET, Dapper échoue. Si je commente une colonne offensante de mon POCO, tout fonctionne.

Voici une paire de lignes pour illustrer:

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

La première colonne est vue dans .NET comme int , la deuxième colonne comme type OracleDecimal et la troisième comme décimale . Le second est le problème.

Par exemple, supprimer Dapper pour le moment et utiliser ODP.NET pour accéder à ces enregistrements indique le problème:

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

Le peu de navigation et de point d'arrêt que j'ai effectué dans le fichier SqlMapper.cs de Dapper me montre qu'il extrait des données du lecteur avec GetValue () / GetValues ​​(), comme ci-dessus, ce qui échoue.

Des suggestions sur comment corriger Dapper? Merci beaucoup.

METTRE À JOUR:

Après réflexion, je RTFMed: Section 3, «Obtention de données à partir d’un objet OracleDataReader» du Guide du développeur Oracle Data Provider pour .NET, qui explique. Pour les colonnes NUMBER, OracleDataReader d'ODP.NET essaiera une séquence de types .NET de Byte à Decimal pour empêcher le débordement. Mais un NUMBER peut toujours déborder Decimal, donnant une exception de conversion invalide si vous essayez l'un des accesseurs de type .NET (GetValue () / GetValues ​​()) du lecteur, auquel cas vous devez utiliser l'accesseur de type ODP.NET du lecteur GetProviderSpecificValue ( ), qui vous donne un OracleDecimal, et s'il déborde un Decimal, sa propriété Value vous donnera une exception de dépassement de capacité et votre seul recours est de le contraindre à un type inférieur avec l'une des méthodes ToXxx () d'OracleDecimal.

Mais bien sûr, l'accesseur de type ODP.NET ne fait pas partie de l'interface IDataReader utilisée par Dapper pour contenir les objets lecteur. Il semble donc que Dapper soit, en soi, incompatible avec Oracle lorsqu'un type de colonne débordera tous les types .NET.

La question demeure: les gens intelligents savent-ils comment étendre Dapper pour gérer cela? Il me semble que j'aurais besoin d'un point d'extension où je pourrais fournir une implémentation sur la manière d'utiliser le lecteur (le forcer à utiliser GetDouble () au lieu de GetValue () ou à OracleDataReader et à appeler GetProviderSpecificValue ()) pour certaines propriétés POCO ou les types de colonne.

Réponse populaire

Pour éviter ce problème, j'ai utilisé:

CAST(COLUMN AS BINARY_DOUBLE)

ou TO_BINARY_DOUBLE(COLUMN)

Dans les types Oracle listés ici, il est décrit comme suit:

Nombre à virgule flottante de 64 bits. Ce type de données nécessite 9 octets, y compris l'octet de longueur.

La plupart des autres types de nombres utilisés par Oracle ont une taille maximale de 22 octets, ce qui est le cas pour .NET



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi