문제
Oracle의 공식 .NET Core 드라이버를 사용하면서 정밀도 관련 문제가 발생했습니다.
코드 예제에서는 1/3의 수학 연산을 수행할 때 OracleCommand.ExecuteScalar() 또는 OracleDataReader.GetDecimal(0)가 모두 InvalidCastException: 지정된 캐스트는 유효하지 않습니다. 오류를 반환합니다.
var connectionString = "Data Source=localhost/XE;User ID=system;Password=oracle";
using (var conn = new OracleConnection(connectionString)) {
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "select 1/3 from dual";
// InvalidCastException 발생
// var result = cmd.ExecuteScalar();
using (var reader = cmd.ExecuteReader()) {
if (reader.HasRows) {
while (reader.Read()) {
// InvalidCastException 발생
var value = reader.GetDecimal(0);
}
}
}
}
원인 분석 및 해결
문제의 원인은 데이터 타입 매핑 불일치에 있습니다. Oracle이 반환하는 데이터 타입과 C#에서 처리하는 방식 사이에 차이가 있습니다. 이를 해결하기 위해 OracleDecimal 타입을 사용하고, OracleDataReader.GetOracleDecimal() 메서드로 값을 읽어야 합니다.
var connectionString = "Data Source=localhost/XE;User ID=system;Password=oracle";
using (var conn = new OracleConnection(connectionString)) {
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "select 1/3 from dual";
using (var reader = cmd.ExecuteReader()) {
if (reader.HasRows) {
while (reader.Read()) {
var original = reader.GetOracleDecimal(0);
Console.WriteLine(String.Join(",", original.BinData));
}
}
}
}
여기서 original 변수를 Decimal로 변환하려고 할 때 다음과 같은 시도들이 실패하였습니다:
(Decimal)original:OverflowExceptionConvert.ChangeType(original, TypeCode.Decimal):InvalidCastExceptionBitConverter.ToDouble(original.BinData, 0): 잘못된 값 반환
최종적으로, OracleDecimal 객체를 C#의 Decimal로 적절히 변환하려면 아래와 같이 직접 바이트 배열을 조작해야 합니다:
OracleDecimal ToDotNetDecimal(OracleDecimal oracleDec) {
byte[] bytes = new byte[22];
bytes[0] = 15;
Array.Copy(oracleDec.BinData, 1, bytes, 1, 15);
return new OracleDecimal(bytes);
}