Oracle 드라이버에서 발생하는 정밀도 문제 해결 방법

문제

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로 변환하려고 할 때 다음과 같은 시도들이 실패하였습니다:

  1. (Decimal)original: OverflowException
  2. Convert.ChangeType(original, TypeCode.Decimal): InvalidCastException
  3. BitConverter.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);
}

태그: Oracle .NET Core OracleDecimal 데이터타입매핑 오류해결

8월 25일 23:59에 게시됨