현재 진행 중인 프로젝트에서 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 의 버전 변경이나 다른 데이터 유형등에 의해서 언제든 오류가 발생할 수 있다.. ㅠㅠ.
댓글
댓글 쓰기