根本原因是你用 executenonquery() 或 executescalar() 读 ref cursor,而只有 executereader() 会触发游标数据读取;必须显式设 oracledbtype.refcursor、commandtype.storedprocedure、bindbyname=true,并用 dynamicparameters 声明输出参数。

根本原因不是参数没设对,而是你用了 ExecuteNonQuery() 或 ExecuteScalar() 去读 REF CURSOR —— 这俩方法根本不处理输出游标。
为什么 ExecuteNonQuery() 拿不到 REF CURSOR 输出值
Oracle 存储过程里定义的 p_result OUT SYS_REFCURSOR 是一个服务器端内存句柄,不是普通变量。ODP.NET 不会把它“返回”给 ExecuteNonQuery() 的返回值,也不会塞进 Parameters 集合的 Value 属性里就完事。
-
ExecuteNonQuery()只返回影响行数(int),对OUT参数完全不触发游标数据读取 - 调用后直接访问
refCursorParam.Value会是null或抛InvalidOperation - 真正打开游标、传输结果集的动作,只发生在
ExecuteReader()调用时
为什么 ExecuteScalar() 也失败
ExecuteScalar() 本意是取结果集第一行第一列,但它内部仍依赖 ExecuteReader();而 ODP.NET 在未显式声明 OracleDbType.RefCursor 的前提下,根本不会把那个 OUT 参数识别为可读游标 —— 所以它要么报 ORA-06550: PLS-00306,要么静默返回 null。
- 错误现象:
ORA-06550: line X, column Y: PLS-00306: wrong number or types of arguments - 本质是参数绑定失败:驱动没把
p_result当作游标传过去,Oracle 端收不到对应参数 - 即使参数名、方向都对,
OracleDbType缺失或写成Object/Xml,照样绑定失败
必须用 ExecuteReader() + 显式声明 RefCursor 类型
只有 ExecuteReader() 会主动检查所有 Output 参数中类型为 OracleDbType.RefCursor 的项,并在执行时让 Oracle 把游标内容流式发回客户端。
-
OracleCommand.CommandType必须设为CommandType.StoredProcedure,不能是Text -
OracleParameter必须同时满足:OracleDbType = OracleDbType.RefCursor、Direction = ParameterDirection.Output - 连接必须处于
Open状态,且在整个reader.Read()过程中保持打开 —— REF CURSOR 依赖活跃连接 - 别漏掉
BindByName = true,否则参数顺序错位会导致绑定到错误的 PL/SQL 形参上
Dapper 场景下容易忽略的绑定细节
Dapper 本身不解析 REF CURSOR,它只是把参数透传给底层 ODP.NET。如果你用 Query<t>()</t> 直接调存储过程名,Dapper 默认按文本 SQL 处理,压根不会去查 Parameters 里的游标声明。
- 必须用
DynamicParameters,显式加参数:p.Add("p_result", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output) - 必须指定
commandType: CommandType.StoredProcedure,否则 ODP.NET 不启用游标绑定逻辑 - 存储过程中
OUT参数名(如p_result)大小写必须和 PL/SQL 定义完全一致,Oracle 默认大写,但若用双引号定义则严格区分
最常被跳过的动作:你以为加了参数就完了,其实没调 ExecuteReader() 或没用 DynamicParameters 显式声明类型,游标就永远卡在 Oracle 服务端内存里,连第一个字节都不会发出来。











