oracle.manageddataaccess.core仅支持commandtype.storedprocedure模式调用纯过程名,不解析exec或begin...end匿名块;需严格匹配包名、参数名大小写、类型及方向,避免重载与pl/sql特有语法。
oracle.manageddataaccess.core 不解析 pl/sql 匿名块包装的存储过程调用
你写 exec check_partid_mark(?, ?) 或 begin check_partid_mark(:p1, :p2); end;,.net core 驱动会把它当普通 sql 执行,不走存储过程绑定路径——结果就是参数根本没传进去,或报 ora-00900: invalid sql statement。驱动只认 commandtype.storedprocedure 模式下的纯过程名(如 "check_partid_mark"),且要求所有参数必须显式添加到 command.parameters 中。
常见错误现象:
- 调用成功但输出参数始终为
null或默认值 - 报错
ORA-06550: line 1, column 7: PLS-00306: wrong number or types of arguments,而实际参数个数完全正确 - 过程在 SQL*Plus 里能跑,C# 里死活不进
实操建议:
- 不要用
EXEC或BEGIN...END包裹调用;直接设command.CommandType = CommandType.StoredProcedure - 过程名必须严格匹配包内声明(含大小写),推荐写全名:
"MY_PACKAGE.CHECK_PARTID_MARK" - 确保每个
OracleParameter的ParameterName和过程定义中一致(通常全大写,如"P_ID",不是"p_id"或"@p_id") - 输入参数即使为
null,也要显式赋值为DBNull.Value;输出参数必须设Direction = ParameterDirection.Output
重载存储过程在 .NET Core 下无法自动分辨
Oracle 允许同名过程在同一个包里重载(overload),比如 CHECK_PARTID_MARK(p_id NUMBER) 和 CHECK_PARTID_MARK(p_id VARCHAR2)。但 Oracle.ManagedDataAccess.Core 不查 ALL_ARGUMENTS 元数据来匹配签名,它只按你传入的参数类型列表“硬匹配”——类型稍有偏差(如 .NET 的 int 对 Oracle 的 NUMBER(5) 而非 NUMBER(10,0)),就可能绑到另一个重载版本上,导致参数个数对不上。
实操建议:
- 执行
SELECT object_name, overload, position, data_type FROM all_arguments WHERE package_name = 'MY_PACKAGE' AND object_name = 'CHECK_PARTID_MARK' ORDER BY overload, position确认重载情况 - 优先避免重载:给不同逻辑的过程起不同名字,比依赖重载更可控
- 若必须用重载,调用时严格按目标版本的参数顺序、类型、精度传参;比如要调用接受
NUMBER(5)的版本,就别传int.MaxValue(它会被映射为NUMBER(10,0)) - 显式指定完整包名+过程名,减少驱动歧义空间
某些 Oracle 特有语法在托管驱动中无对应实现
Oracle.ManagedDataAccess.Core 是纯托管实现,不复用 Oracle 客户端的 PL/SQL 引擎。像 PRAGMA AUTONOMOUS_TRANSACTION、%ROWTYPE 绑定、隐式游标 SQL%ROWCOUNT 这类深度耦合 Oracle 内核的语法,驱动层根本不处理——它只负责把参数序列化后发给服务器,返回结果也只按标准 OCI 协议解包。所以你在 C# 里调用一个用了 PRAGMA 的过程,不会报错,但事务行为可能和 Oracle 本地执行不一致。
实操建议:
- 不要指望驱动“理解”PL/SQL 语义;它只做参数搬运工
- 涉及自治事务、复杂游标、动态 SQL(
EXECUTE IMMEDIATE)的存储过程,务必在 Oracle 侧做充分测试,不能仅靠 .NET 调用通过就认为 OK - 输出游标(
REF CURSOR)必须显式声明OracleDbType.RefCursor,且不能省略Direction = ParameterDirection.Output;否则驱动无法识别为游标,会当作普通参数丢弃 - 字符串参数长度未指定
Size时,驱动可能截断或触发隐式转换,导致绑定失败或数据失真
连接字符串里无效参数造成静默降级
.NET Core 下的 Oracle.ManagedDataAccess.Core 只认有限几个连接字符串参数,其余一概忽略。比如你写了 Unicode=True、Failover=true、Load Balancing=True,这些在 .NET Framework 时代有效的配置,在 .NET Core 里既不报错也不生效——驱动直接走默认路径,可能导致连接池行为异常、故障转移失效、字符集处理偏差等问题。
实操建议:
- 只保留必需参数:
Data Source、User Id、Password、Connection Timeout、Pooling、Statement Cache Size -
Data Source推荐用 Easy Connect 格式(如"dbhost:1521/ORCLPDB1"),比完整描述符更易维护;若必须用描述符,确保括号嵌套和等号位置完全正确 - 调试连接问题时,临时设
Pooling=false,排除连接池干扰;设Statement Cache Size=0避免首次查询因元数据请求失败而卡住 - 不要依赖
TNS_ADMIN环境变量里的tnsnames.ora别名——.NET Core 驱动不读这个文件,别名必须手动拼进Data Source
关键点在于:.NET Core 的 Oracle 驱动不是 Oracle 客户端的封装,它是一套独立协议栈。任何假设“它该支持 Oracle 什么就支持什么”的想法,都会在第一次 PLS-00306 报错时被打破。真正可靠的路径,是让存储过程本身尽可能简单、明确、无重载、无强依赖 Oracle 内部机制,并在 C# 层严格对齐参数定义。











