기본 콘텐츠로 건너뛰기

[ODP.NET] Empty Array 처리하기... 에러 OracleParameter.Value is invalid...

현재 진행 중인 프로젝트에서 Oracle 의 팩키지를 기준으로 업무 처리를 하고 클라이언트 어플리케이션과는 Array (PLSQLAssociativeArray) 방식으로 파라미터를 연동하고 있다.

그런데 Empty Array 처리가 되어야 한다고 해서, 열심히 ODP.NET Array 연동 부분을 검토해 본 결과, 정상적인 방법으로는 처리가 되지 않고, 다른 문서들에서도 버그다, 지원되지 않는다는 말 뿐이었다.

그러나 기능은 제공되어야 하기 때문에 (제공하지 않으면 너무 많은 부분을 수정해야 하기 때문에.. ㅠㅠ) Reflection으로 오류나는 메서드의 처리 조건들을 모두 검토하여 해결은 했다.

나중에 Oracle Array + ODP.NET 을 사용하는 환경에서 재 활용할 수 있도록 정리해 놓도록 한다.

해결하게 된 근본적인 원리는 다음과 같다.

Oracle Document 의 내용
...
ODP.NET does not support binding an empty PL/SQL Associative Array. Therefore, Size cannot be set to 0 when OracleParameter object is used to bind a PL/SQL Associate Array.
...

위의 내용을 근거로 하면 일단 Array Size는 무조건 0보다는 커야 한다.

- Reflection 처리 내용을 보면 (ResetCtx 메서드) 에서 값의 검증 과정에서 Array 인 경우 null, DBNull.Value는 허용되지 않는다.

위의 내용을 근거로 하면 null 이 아닌 Array 형식으로 값이 무조건 제공되어야 한다.

- Reflection 처리 내용을 보면 (ResetCtx 메서드) 에서 Array이면서 null 이거나 DBNull.Value 인 경우는 ArrayBindStatus가 존재하는지를 검증한다.

위의 내용을 근거로 하면 Empty Array 처리를 하기 위해서는 추가적인 정보로 ArrayBindStatus 가 존재하여야 한다.

다시 한번 정리를 하면...

  • Size는 0 보다 크게 지정되어야 한다.
  • null, DBNull.Value 가 아닌 Array 형식으로 값을 설정해 주어야 한다.
  • ArrayBindStatus 정보가 존재하여야 한다.
이 기준으로 근거로 다음과 같이 설정하면 처리가 가능하다. (물론 더 세밀하게 조정을 해 보면 간략화 시킬 수 있겠지만,.. 현재는 이거로 만족)

[ 적용 샘플 코드 ]

OracleParameter oraParam = new OracleParameter("parameterName", OracleDbType.Varchar2, null, ParameterDirection.Input);
oraParam.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

if (oraParam.Value.IsNull()) {
    // Array 구성 항목의 데이터 길이를 1자리 개의 배열로 임의 설정한다. (값은 null 이므로 임의로 설정)
    oraParam.ArrayBindSize = Enumerable.Repeat(1, 1).ToArray();
    switch(oraParam.OracleDbType)(
        case OracleDbType.Char:
        case OracleDbType.NChar:
        case OracleDbType.Varchar2:
        case OracleDbType.NVarchar2:
            // null 이 아닌 값으로 전환한다.
            oraParam.Value = new OracleString[] { OracleString.Null };
            break;
        case OracleDbType.Decimal:
        case OracleDbType.Double:
        case OracleDbType.Long:
            // null 이 아닌 값으로 전환한다.
            oraParam.Value = new OracleDecimal[] { OracleDecimal.Null };
            break;
        default:
            throw new Exception("Empty Array Binding이 지원되지 않는 형식입니다.");
    }

    // Array 크기를 0 보다 크게 지정한다.
    oraParam.Size = 1;
    // ArrayBindStatus 를 설정한다. (배열 크기 지정한 갯수 만큼)
    oraParam.ArrayBindStatus = new OracleParameterStatus[] {
        OracleParameterStatus.NullInsert;
    };
} else {
    ....
}


위의 코드 주석을 보면 상기에서 분석(유추)했던 오류 원인을 피해가는 코드임을 알 수 있다.

[[ 주의 ]]
억지로 Deassemble  하여 오류 검증 처리를 피해간 것이므로, 이후에 ODP.NET 의 버전 변경이나 다른 데이터 유형등에 의해서 언제든 오류가 발생할 수 있다.. ㅠㅠ.

댓글