如何解决C#调用含自定义对象OUT参数的Oracle存储过程绑定错误
Oracle 19存储过程调用问题(.NET 4.6.1 + VS2015)
问题场景
使用VS2015搭配.NET 4.6.1框架调用Oracle 19的存储过程时触发报错:
- 存储过程包含2个输入参数、2个输出参数,其中一个OUT参数返回自定义对象类型
table_name - 存储过程定义:
GetSomething(date IN VARCHAR2, code IN VARCHAR2, response OUT table_name, count OUT NUMBER)
- 自定义对象类型定义:
CREATE TYPE table_name AS OBJECT ( column_1 data_type, column_2 data_type, -- 共20个字段 );
- 编写的C#调用代码:
using Oracle.DataAccess.Client; OracleConnection con = new OracleConnection(); con.ConnectionString = "Connection string here"; OracleCommand cmd = new OracleCommand(); cmd.CommandText = "SP name"; cmd.CommandType = CommandType.StoredProcedure; cmd.Connection = con; cmd.Parameters.Add("date","01/01/2020"); cmd.Parameters.Add("code", "123"); cmd.Parameters.Add("count", OracleDbType.Int64).Direction = ParameterDirection.Output; cmd.Parameters.Add(new OracleParameter { ParameterName = "response", SourceColumn = "table_name", OracleDbType = OracleDbType.Array, CollectiveType = OracleCollectionType.PLSQLAssociativeArray });
- 报错情况:设置
CollectiveType时提示“response参数绑定错误”;移除该属性则提示“参数数量或类型参数错误”
问题根源
- 类型匹配错误:你把单个自定义对象(
table_name是OBJECT类型)当成了集合/数组处理,OracleDbType.Array和PLSQLAssociativeArray是用来绑定Oracle的集合类型(比如TABLE OF table_name或VARRAY),但这里存储过程返回的是单个OBJECT实例,不是集合。 - 缺少对象映射:Oracle自定义OBJECT类型需要在.NET中定义对应的实体类,并配置映射关系,否则驱动无法解析返回的对象。
- 参数绑定细节遗漏:比如未指定自定义对象的完整类型名,参数方向未设置为Output,还有代码未包含连接打开、命令执行的逻辑。
解决方案
步骤1:定义C#实体类映射Oracle自定义对象
创建与table_name字段一一对应的实体类,并添加Oracle对象映射特性:
using Oracle.DataAccess.Types; [OracleObjectMappingAttribute("TABLE_NAME")] // 与Oracle中类型名完全一致,注意Oracle默认大写 public class TableName : OracleCustomTypeBase<TableName> { [OracleObjectMappingAttribute("COLUMN_1")] public string Column1 { get; set; } // 根据Oracle实际data_type调整类型,比如NUMBER对应int/decimal,VARCHAR2对应string [OracleObjectMappingAttribute("COLUMN_2")] public int Column2 { get; set; } // 依次添加剩余18个字段的映射,字段名对应Oracle对象的列名 } // 注册自定义类型工厂 [OracleCustomTypeMappingAttribute("你的用户名.TABLE_NAME")] // 替换为实际的Oracle用户名+类型名 public class TableNameFactory : OracleCustomTypeFactory<TableName> { }
步骤2:修正C#调用代码
调整参数绑定逻辑,正确处理自定义对象参数:
using Oracle.DataAccess.Client; using Oracle.DataAccess.Types; // 初始化连接 using (OracleConnection con = new OracleConnection("Connection string here")) { con.Open(); using (OracleCommand cmd = new OracleCommand()) { cmd.CommandText = "GETSOMETHING"; // 存储过程名注意大小写,Oracle默认大写 cmd.CommandType = CommandType.StoredProcedure; cmd.Connection = con; // 添加输入参数 cmd.Parameters.Add("DATE", OracleDbType.Varchar2).Value = "01/01/2020"; cmd.Parameters.Add("CODE", OracleDbType.Varchar2).Value = "123"; // 添加输出参数count cmd.Parameters.Add("COUNT", OracleDbType.Int64).Direction = ParameterDirection.Output; // 添加输出参数response(自定义对象) OracleParameter responseParam = new OracleParameter { ParameterName = "RESPONSE", OracleDbType = OracleDbType.Object, UdtTypeName = "你的用户名.TABLE_NAME", // 必须指定自定义类型的完整名称 Direction = ParameterDirection.Output }; cmd.Parameters.Add(responseParam); // 执行存储过程 cmd.ExecuteNonQuery(); // 获取输出结果 long count = (long)cmd.Parameters["COUNT"].Value; TableName response = (TableName)responseParam.Value; // 处理结果 Console.WriteLine($"Count: {count}"); Console.WriteLine($"Column1: {response.Column1}"); } }
额外注意事项
- 确保Oracle Data Access Components (ODAC)版本兼容:VS2015 + .NET4.6.1需要对应支持Oracle19的ODAC版本,避免版本不兼容问题。
- 存储过程中的
date是Oracle关键字,建议重命名参数名,或者调用时用双引号包裹(如"DATE"),避免语法冲突。 - 实体类的属性类型必须和Oracle对象的字段类型严格匹配,比如Oracle的
NUMBER(10)对应C#的int,VARCHAR2(50)对应string。
内容的提问来源于stack exchange,提问作者SRPCode
相关产品推荐
相关产品推荐

