必须使用 oracle.manageddataaccess 驱动和 dapper.oracle 的 oracledynamicparameters,并通过 query() 或 querymultiple() 调用,且存储过程中需显式 open ref cursor,否则无法获取结果。
oracledbtype.refcursor 没显式声明,或者用了不支持的驱动或参数封装方式,基本就拿不到结果。
DynamicParameters 不能直接用 OracleDbType.RefCursor
Dapper 原生的 DynamicParameters 不认识 OracleDbType.RefCursor,硬塞进去会抛异常:“无法将 OracleRefCursor 转换为 DataTable 或 IEnumerable
必须换用 Dapper.Oracle 提供的 OracleDynamicParameters:
- 安装 NuGet 包:
Dapper.Oracle(注意不是Dapper单独包) - 代码里 new 的是
new OracleDynamicParameters(),不是DynamicParameters() -
Add()时只写dbType: OracleDbType.RefCursor,别设size(RefCursor 不需要)
没用 Oracle.ManagedDataAccess 驱动
旧驱动 System.Data.OracleClient 已废弃,Oracle.DataAccess(非托管版)对 Ref Cursor 支持不稳定,尤其在 .NET Core 下容易卡在“未找到数据类型”错误。
必须确认项目引用的是:
- NuGet 包:
Oracle.ManagedDataAccess(推荐 23.x+ 版本) - 连接字符串无需额外加游标开关,默认就支持
- 不要混用多个 Oracle 驱动——删掉
Oracle.DataAccess和System.Data.OracleClient引用
调用方式写成 Execute() 或 QueryMultiple() 错了
Ref Cursor 必须靠 Query<t>()</t> 或 QueryMultiple() 触发读取,Execute() 只执行、不打开游标;ExecuteNonQuery() 更不行——它返回后 OracleParameter.Value 仍是 null。
正确姿势:
- 单个 Ref Cursor:用
connection.Query<user>("pkg.get_users", p, commandType: CommandType.StoredProcedure)</user> - 多个 Ref Cursor:用
connection.QueryMultiple(...),再依次调用reader.Read<user>()</user>、reader.Read<order>()</order> - 别在
Query()前手动读p.Get<oraclerefcursor>("p_cursor")</oraclerefcursor>——Dapper.Oracle 已内部处理
存储过程里没真正 OPEN ... FOR
哪怕参数声明了 p_result OUT SYS_REFCURSOR,如果 PL/SQL 块里漏了 OPEN p_result FOR SELECT ...,C# 端收到的就是空游标,Query<t>()</t> 返回空集合,也不报错。
排查方法:
- 在 SQL*Plus 里手动执行:
var rc refcursor; exec pkg.get_data(:rc); print rc; - 检查
all_arguments视图确认参数方向是OUT,类型是REF CURSOR - 多个 Ref Cursor 时,每个都得有对应
OPEN,哪怕返回空结果也要OPEN p_x FOR SELECT * FROM DUAL WHERE 1=0
Ref Cursor 的绑定完全依赖参数名、类型、方向三者严格匹配,少一个环节就静默失败。最容易被忽略的是驱动选型和 OracleDynamicParameters 替换——这两步跳过,后面全白搭。











