You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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参数绑定错误”;移除该属性则提示“参数数量或类型参数错误”

问题根源

  1. 类型匹配错误:你把单个自定义对象(table_name是OBJECT类型)当成了集合/数组处理,OracleDbType.Array和PLSQLAssociativeArray是用来绑定Oracle的集合类型(比如TABLE OF table_name或VARRAY),但这里存储过程返回的是单个OBJECT实例,不是集合。
  2. 缺少对象映射:Oracle自定义OBJECT类型需要在.NET中定义对应的实体类,并配置映射关系,否则驱动无法解析返回的对象。
  3. 参数绑定细节遗漏:比如未指定自定义对象的完整类型名,参数方向未设置为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:00:46