C#传递UDT对象数组至Oracle存储过程触发‘Column contains NULL data’异常
问题原因及解决办法
核心原因1:Oracle数组类型与C#参数配置不匹配
你在Oracle包中定义的T_EMTEST_ARRAY是嵌套表(table of EMTEST),但C#端参数的CollectionType设置为OracleCollectionType.PLSQLAssociativeArray,这两种类型不兼容。PLSQL关联数组要求Oracle端必须定义为table of ... index by binary_integer,类型不匹配会导致数据序列化时出错,触发"Column contains NULL data"异常。
核心原因2:Employee类缺少无参构造函数
Oracle.ManagedDataAccess在处理UDT(自定义类型)时,需要通过无参构造函数实例化对象,你的Employee类仅提供了带参构造,这会导致UDT序列化/反序列化过程中无法正确创建实例,进而引发空数据相关的转换异常。
核心原因3:INullable接口实现及null值处理不当
Null属性返回的实例中,你给Id和Name设置了默认值(0和空字符串),而非保持null,不符合Oracle UDT的null语义。FromCustomObject和ToCustomObject方法中未正确处理C# null与Oracle DBNull的转换,直接传递null会导致Oracle无法识别,触发异常。
具体解决步骤
步骤1:修正Oracle端数组类型为PLSQL关联数组
修改包头部的数组定义,添加index by binary_integer:
-- 包头部 type T_EMTEST_ARRAY is table of EMTEST index by binary_integer; procedure TestGetObjectsBack( Employes in T_EMTEST_ARRAY, ResultTest OUT RC_Result );
步骤2:修正Employee类的实现
添加无参构造函数,修正Null属性,完善null值处理逻辑:
[OracleCustomTypeMapping("EMTEST")] public class Employee : IOracleCustomType, INullable { // 必须添加无参构造函数,供Oracle驱动实例化对象 public Employee() { } public Employee(int? id, string name) { Id = id; Name = name; } [OracleObjectMapping("Name")] public string Name { get; set; } [OracleObjectMapping("Id")] public int? Id { get; set; } public bool IsNull { get; set; } // 返回真正的Null实例,不设置任何字段值 public static Employee Null => new Employee { IsNull = true }; public void FromCustomObject(OracleConnection con, object udt) { // 将C# null转换为Oracle可识别的DBNull.Value OracleUdt.SetValue(con, udt, "Id", Id ?? DBNull.Value); OracleUdt.SetValue(con, udt, "Name", Name ?? DBNull.Value); } public void ToCustomObject(OracleConnection con, object udt) { // 将Oracle返回的DBNull转换为C# null var idValue = OracleUdt.GetValue(con, udt, "Id"); Id = idValue == DBNull.Value ? null : (int?)idValue; var nameValue = OracleUdt.GetValue(con, udt, "Name"); Name = nameValue == DBNull.Value ? null : (string)nameValue; } }
步骤3:修正C#端参数配置
确保参数的OracleDbType与数组类型匹配,这里使用OracleDbType.Array:
var employeParam = new OracleParameter("Employes", OracleDbType.Array, ParameterDirection.Input); employeParam.CollectionType = OracleCollectionType.PLSQLAssociativeArray; employeParam.Size = employeArray.Length; employeParam.UdtTypeName = "PKS_CARAT.T_EMTEST_ARRAY"; employeParam.Value = employeArray;
完成以上修改后,重新测试调用,应该可以解决"Column contains NULL data"的异常。
内容的提问来源于stack exchange,提问作者Birtija
相关产品推荐
相关产品推荐

