I'm trying to create a test app that will pass an array of objects (in my case Employees) to an Oracle stored procedure.
When I call the ExecuteReader
to call the procedure, I get an error
Column contains NULL data
but I have no idea what that means.
Here is the code I use. I have the following class:
[OracleCustomTypeMapping("EMTEST")]
public class Employee : IOracleCustomType, INullable
{
public Employee(int? Id, string Name)
{
this.Id = Id;
this.Name = Name;
}
[OracleObjectMapping("Name")]
public string Name { get; set; }
[OracleObjectMapping("Id")]
public int? Id { get; set; }
public bool IsNull { get; set; }
public static Employee Null => new Employee(0, "") { IsNull = true };
public void FromCustomObject(OracleConnection con, object udt)
{
OracleUdt.SetValue(con, udt, "Id", Id);
OracleUdt.SetValue(con, udt, "Name", Name);
}
public void ToCustomObject(OracleConnection con, object udt)
{
Id = ((int?)(OracleUdt.GetValue(con, udt, "Id")));
Name = ((string)(OracleUdt.GetValue(con, udt, "Name")));
}
}
On oracle side i create a type:
create or replace TYPE EMTEST AS OBJECT
(
Id number null,
Name varchar2(50) null
);
And a procedure in a package called PKS_CARAT
This is the header (where the table of the type is defined) :
type T_EMTEST_ARRAY is table of EMTEST;
procedure TestGetObjectsBack(
Employes in T_EMTEST_ARRAY,
ResultTest OUT RC_Result
);
This is the body:
procedure TestGetObjectsBack(
Employes in T_EMTEST_ARRAY,
ResultTest OUT RC_Result
)
is
begin
OPEN ResultTest FOR
select 1 as Id,'mika' as Name from dual;
-- select e.Id,e.Name from table (Employes) e;
end TestGetObjectsBack;
This is the code that calls the stored procedure:
var oracleConnection = new OracleConnection("User Id=xxx;Password=xxx;Data Source=ORAKISDEV2;Connection Lifetime=10;Min Pool Size=1;Max Pool Size=200;");
var employeList = new List<Employee>()
{
new Employee(1,"Zoki"),
new Employee(2, "Pera"),
};
var employeArray = employeList.ToArray();
var employeParam = new OracleParameter("Employes", OracleDbType.Object, ParameterDirection.Input);
employeParam.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
employeParam.Size = employeArray.Length;
employeParam.UdtTypeName = "PKS_CARAT.T_EMTEST_ARRAY";
employeParam.Value = employeArray;
var cursor = new OracleParameter("ResultTest", OracleDbType.RefCursor, ParameterDirection.Output);
oracleConnection.Open();
using (var oracleCommand = oracleConnection.CreateCommand())
{
oracleCommand.Connection = oracleConnection;
oracleCommand.CommandText = "PKS_CARAT.TestGetObjectsBack";
oracleCommand.CommandType = CommandType.StoredProcedure;
oracleCommand.BindByName = true;
oracleCommand.Parameters.Add(employeParam);
oracleCommand.Parameters.Add(cursor);
var reader = oracleCommand.ExecuteReader();
....
I read many articles, and the most important are:
- pass array of objects to oracle stored procedure using ODP.Net managed client
- Why do I get "Invalid Parameter binding" when using Oracle stored procedure with Udt and C#
I tried many sugesstions but none of them made any difference. I still get the Column contains NULL data without any explanation which data is null or why this issue is caused. I checked if my columns from the class and the oracle type are the same and it look slike they are.
Full exception text is: 'Column contains NULL data'. From 'Oracle.ManagedDataAccess'
Type of the exception is System.InvalidCastException
Im using nuget package Oracle.ManagedDataAccess.Core version 3.21.80
Here is the top of the stack trace of the exception:
OracleInternal.UDT.Types.UDTNamedType.GetNamedTypeMetaData(OracleConnection conn, OracleCommand getTypeCmd)
at OracleInternal.UDT.Types.UDTTypeCache.GetMetaData(OracleConnection conn, UDTNamedType udtType)
at OracleInternal.UDT.Types.UDTTypeCache.CreateUDTType(OracleConnection conn, String schemaName, String typeName)
at OracleInternal.UDT.Types.UDTTypeCache.GetUDTType(OracleConnection conn, String schemaName, String typeName)
at OracleInternal.ConnectionPool.OraclePoolManager.GetUDTType(OracleConnection conn, String schemaName, String typeName)
at Oracle.ManagedDataAccess.Client.OracleConnection.GetUDTTypeFromCache(String schemaName, String typeName)
at Oracle.ManagedDataAccess.Client.OracleParameter.GetUDTType(OracleConnection conn)
at Oracle.ManagedDataAccess.Client.OracleParameter.PreBind_UDT(OracleConnection conn)
at Oracle.ManagedDataAccess.Client.OracleParameter.PreBind(OracleConnectionImpl connImpl, ColumnDescribeInfo cachedParamMetadata, Boolean& bMetadataModified, Int32 arrayBindCount, ColumnDescribeInfo& paramMetaData, Object& paramValue, Boolean isEFSelectStatement, SqlStatementType stmtType)
at OracleInternal.ServiceObjects.OracleCommandImpl.InitializeParamInfo(ICollection paramColl, OracleConnectionImpl connectionImpl, ColumnDescribeInfo[] cachedParamMetadata, Boolean& bMetadataModified, Boolean isEFSelectStatement, MarshalBindParameterValueHelper& marshalBindValuesHelper)
at OracleInternal.ServiceObjects.OracleCommandImpl.ProcessParameters(OracleParameterCollection paramColl, OracleConnectionImpl connectionImpl, ColumnDescribeInfo[] cachedParamMetadata, Boolean& bBindMetadataModified, Boolean isEFSelectStatement, MarshalBindParameterValueHelper& marshalBindValuesHelper)
at OracleInternal.ServiceObjects.OracleCommandImpl.ExecuteReader(String commandText, OracleParameterCollection paramColl, CommandType commandType, OracleConnectionImpl connectionImpl, OracleDataReaderImpl& rdrImpl, Int32 longFetchSize, Int64 clientInitialLOBFS, OracleDependencyImpl orclDependencyImpl, Int64[] scnForExecution, Int64[]& scnFromExecution, OracleParameterCollection& bindByPositionParamColl, Boolean& bBindParamPresent, Int64& internalInitialLOBFS, Int64 internalInitialJSONFS, OracleException& exceptionForArrayBindDML, OracleConnection connection, IEnumerable`1 adrianParsedStmt, Boolean isDescribeOnly, Boolean isFromEF)
at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior)
at Oracle.ManagedDataAccess.Client.OracleCommand.ExecuteReader()
at OracleArrayTest.Program.TestCollectionCustom() in C:\project\BulkProject\OracleArrayTest\Program.cs:line 203
Does anybody know what am i doing wrong? What is this exception telling me?