ODP.NET Core 8.0 支持 Oracle 存储过程返回 REF CURSOR,但必须用 OracleCommand 显式声明 OracleDbType.RefCursor 类型的输出参数,并配合 OracleDataAdapter 或 ExecuteReader() 调用;不可直接当作返回值,否则报 ORA-06550 错误。
ODP.NET Core 8.0 是否支持 Oracle 存储过程返回 REF CURSOR
支持,但必须用 oraclecommand 显式声明 oracledbtype.refcursor 类型的输出参数,并配合 oracledataadapter 或手动调用 executereader()。直接把 ref cursor 当作返回值(像 sql server 的 datatable 那样)会报错:ora-06550: pls-00306: wrong number or types of arguments —— 这是因为 odp.net 不自动绑定游标输出参数。
调用带 OUT REF CURSOR 的存储过程的最小可行代码
假设 Oracle 有如下存储过程:
CREATE OR REPLACE PROCEDURE GET_EMPLOYEES(p_result OUT SYS_REFCURSOR) AS BEGIN OPEN p_result FOR SELECT employee_id, first_name, last_name FROM employees; END;
.NET 8 中调用它需注意三点:连接字符串启用 WAL(可选但推荐)、命令类型设为 StoredProcedure、输出参数类型和方向必须严格匹配:
-
OracleCommand.CommandType必须设为CommandType.StoredProcedure,不能用Text -
OracleParameter的OracleDbType必须是OracleDbType.RefCursor,Direction必须是ParameterDirection.Output - 执行后不能调用
ExecuteScalar()或ExecuteNonQuery(),必须用ExecuteReader()获取结果集
示例片段:
using (var conn = new OracleConnection(connStr))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "GET_EMPLOYEES";
cmd.CommandType = CommandType.StoredProcedure;
<pre class='brush:php;toolbar:false;'>var refCursorParam = cmd.Parameters.Add("p_result", OracleDbType.RefCursor);
refCursorParam.Direction = ParameterDirection.Output;
using (var reader = cmd.ExecuteReader()) // ← 关键:这里才真正打开游标
{
while (reader.Read())
{
Console.WriteLine($"{reader["employee_id"]}: {reader["first_name"]}");
}
}} }
为什么用 OracleDataAdapter.Fill() 更稳妥?
手动读 OracleDataReader 容易漏掉异常场景:比如存储过程中断、游标未打开、字段名大小写不一致(Oracle 默认大写,C# 默认按原名访问)。而 OracleDataAdapter 会自动处理元数据映射、空值转换和资源释放:
-
Fill()内部会调用ExecuteReader()并构建DataTable,字段名默认按 Oracle 返回的大写名(如"EMPLOYEE_ID"),除非你在OracleCommand上设置BindByName = true - 如果存储过程有多个
REF CURSOR输出参数,Fill()只能取第一个;多个结果集要用ExecuteReader()+NextResult() - 记得在
OracleCommand上显式设置BindByName = true,否则参数顺序错位会导致静默失败
示例:
var table = new DataTable();
using (var adapter = new OracleDataAdapter(cmd))
{
adapter.Fill(table); // 自动映射列,处理 NULL
}常见报错与绕过方式
ORA-01008: not all variables bound:说明某个 IN 参数没赋值,或参数名拼错(注意 Oracle 存储过程参数名区分大小写,但 ODP.NET 默认忽略大小写——除非你关了 BindByName)。
Invalid operation. The connection is closed.:多发生在 OracleDataReader 未关闭就重用 OracleCommand,或在 using 块外访问 reader。
Unable to cast object of type 'Oracle.ManagedDataAccess.Types.OracleRefCursor' to type 'System.Data.DataTable':这是试图把 OracleParameter.Value 直接转成 DataTable,REF CURSOR 不是值对象,必须通过 ExecuteReader() 消费。
最容易被忽略的一点:Oracle 服务端字符集(如 AL32UTF8)和客户端 NLS_LANG 环境变量不一致时,中文字段可能显示为问号——.NET 8 中应优先使用连接字符串里的 Unicode=true,而非依赖系统环境变量。


















