Oracle函数返回值必须用ReturnValue或Output参数显式接收,不能直接用ExecuteScalar或Query;标量类型用ParameterDirection.ReturnValue,REF CURSOR结果集用ParameterDirection.Output,并严格设置commandType: CommandType.StoredProcedure。

Oracle函数返回值必须用OUT参数或REF CURSOR,不能直接用ExecuteScalar
Dapper本身不支持Oracle函数的直接标量返回(比如FUNCTION get_user_name(id NUMBER) RETURN VARCHAR2),因为Oracle驱动要求明确声明参数方向。你如果直接传CommandType.Text去执行SELECT my_pkg.get_user_name(123) FROM DUAL,Dapper会当普通查询处理,但Oracle可能报ORA-06553: PLS-306: wrong number or types of arguments——这不是Dapper的问题,而是驱动没被告诉“这是个函数调用,需要绑定OUT参数”。
- 必须用
CommandType.StoredProcedure,哪怕函数没有IN OUT参数也要这么设 - 函数名要带包名(如
my_pkg.get_user_name),不能只写函数名 - 所有
RETURN值必须映射为DbParameter并设Direction = ParameterDirection.Output或ReturnValue - 对
VARCHAR2/NUMBER等标量类型,用ReturnValue;对结果集,用REF CURSOR+Output参数
标量返回值:用ReturnValue参数接收NUMBER或VARCHAR2
假设你有函数FUNCTION calc_discount(price NUMBER) RETURN NUMBER,正确做法是手动构造OracleParameter,把Direction设为ReturnValue,再让Dapper执行:
var pPrice = new OracleParameter("price", OracleDbType.Int32) { Value = 100 };
var pResult = new OracleParameter("result", OracleDbType.Int32) { Direction = ParameterDirection.ReturnValue };
connection.Execute("my_pkg.calc_discount",
new[] { pPrice, pResult },
commandType: CommandType.StoredProcedure);
int discount = (int)pResult.Value;
-
pResult的名字可以任意(如"ret"),但Direction = ReturnValue必须显式设置 - 不要用
@result这种命名方式——Oracle不认SQL Server风格的命名参数 - 类型必须匹配:函数返回
NUMBER就用OracleDbType.Int32或Decimal,返回VARCHAR2(50)就用OracleDbType.Varchar2并设Size = 50 - Dapper的
Query或ExecuteScalar在这里完全无效,别试
结果集返回值:函数必须返回REF CURSOR,用Output参数接收
如果函数定义是FUNCTION get_users_by_dept(dept_id NUMBER) RETURN SYS_REFCURSOR,那它本质是个“带逻辑的视图”,必须用Output参数接游标,再用Dapper的Query解析:
var pDeptId = new OracleParameter("dept_id", OracleDbType.Int32) { Value = 10 };
var pCursor = new OracleParameter("rc", OracleDbType.RefCursor) { Direction = ParameterDirection.Output };
connection.Query<user>("my_pkg.get_users_by_dept",
new[] { pDeptId, pCursor },
commandType: CommandType.StoredProcedure);</user>
-
pCursor的Direction必须是Output,不是ReturnValue - 函数体里必须有
OPEN rc FOR SELECT ...语句,否则游标为空 - Oracle驱动要求
RefCursor参数名和函数中OPEN语句用的变量名一致(这里都是rc) - 不能省略
commandType: CommandType.StoredProcedure,否则Dapper会尝试用Text模式执行,报ORA-00900: invalid SQL statement
常见报错与绕不过去的细节
最常卡在三件事上:驱动没装对、包权限不足、参数大小写/空格不一致。比如:
-
ORA-06550 / PLS-00306:函数签名和参数绑定不匹配——检查OracleDbType是否和PL/SQL声明一致(NUMBER对应Int32还是Decimal?VARCHAR2(100)有没有设Size?) -
ORA-01008: not all variables bound:漏了某个IN参数,或REF CURSOR参数没加进参数数组 -
ORA-00900或ORA-06553反复出现:确认连接字符串里Unicode=True已启用(尤其含中文时),且Oracle客户端版本和服务器兼容(12c+建议用Oracle.ManagedDataAccess v21.x) - 函数在SQL*Plus里能跑,C#里不行:大概率是包没授权,执行
GRANT EXECUTE ON my_pkg TO your_user
Oracle函数调用不像SQL Server那么直来直去,每个参数都得亲手配方向、类型、大小,少一个Direction设置,就卡死。











