新闻详情

新闻详情

首页 / 资讯中心 / 详情

C# 调用 Oracle 存储过程:OracleCommand 配置 CommandType.StoredProcedure 的完整骨架

发布时间:2026/11/2 18:35:40来源:尧图网络
C# 调用 Oracle 存储过程:OracleCommand 配置 CommandType.StoredProcedure 的完整骨架
1. 为什么你的 OracleCommand 调存储过程总是“静默失败”如果你写过 C# 连 Oracle大概率遇到过这种诡异情况代码不报错连接也正常ExecuteNonQuery()返回 -1 或者 0但去数据库一查存储过程压根没执行数据一条没变。更让人抓狂的是有时候它又“碰巧”能跑通换个参数名就崩了。这个问题的核心往往不在连接字符串也不在权限而是OracleCommand.CommandType CommandType.StoredProcedure这一行背后的“配对规则”没吃透。Oracle 的托管驱动Oracle.ManagedDataAccess和 SQL Server 的SqlCommand在行为上有本质区别SQL Server 会帮你做很多隐式推断而 Oracle 要求你显式声明一切——过程名、参数名、参数方向、参数类型一个都不能含糊。这篇内容适合正在用 C# 对接 Oracle 存储过程的开发者尤其是那些被ORA-06502、ORA-01008或者“无报错但无结果”折磨过的朋友。我会把OracleCommand配置CommandType.StoredProcedure的完整骨架拆开从连接字符串到参数绑定再到 REF CURSOR 读取和事务处理每一步都给可复制的代码。同时我会说明如何用 TaoToken 统一管理 AI 辅助配置时的 Key 和 API 通道让排查过程更顺滑。2. 前置准备TaoToken 统一 Key 与 API 通道在开始写代码之前先解决一个容易被忽略的效率问题当你需要查文档、让 AI 辅助生成 PL/SQL 块或者排查参数类型映射时频繁切换不同的 API Key 和通道会很烦。TaoToken 的作用就是把这些 AI 辅助能力的 Key 和通道统一管起来。你可以先到官网了解整体能力https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 然后进入控制台创建自己的 API Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你更习惯直接看接口文档接入文档在这里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。拿到 Key 之后API 基地址用 https://taotoken.net/api 即可这个地址不加 UTM 参数。对于长期做 C# 编码和 Agent 辅助的场景可以关注 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你只是想先验证模型对话效果模型对话入口在https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。注意TaoToken 在这里的角色是统一管理 AI 辅助通道不是替代你的 Oracle 客户端或编辑器。存储过程调用本身仍然由你的 C# 代码和 Oracle 驱动完成。3. 可复制配置连接字符串与 OracleCommand 完整骨架3.1 连接字符串里必须加 UnicodeTrue很多“参数全对但取 OUT 值乱码”的问题根源就在连接字符串。即使数据库字符集是 AL32UTF8.NET 驱动默认仍按非 Unicode 方式编码字符串。加上UnicodeTrue才会启用 UTF-16 到 UTF-8 的正确转换。string connStr Data SourceORCLPDB1;User Idapp_user;Passwordyour_pwd;UnicodeTrue;Poolingtrue;Min Pool Size1;Max Pool Size20;;如果你用的是 TNS 别名Data Source就写别名如果是 EZConnect可以写成localhost:1521/ORCLPDB1。UnicodeTrue这个配置不影响CommandType的行为但会影响所有字符串参数的传输准确性漏掉它前面参数全对也白搭。3.2 CommandText 必须是纯过程名不能带 call 或 begin/end这是第一个大坑。CommandType.StoredProcedure生效的前提是CommandText与存储过程名完全一致含大小写和包名。using var conn new OracleConnection(connStr); conn.Open(); using var cmd conn.CreateCommand(); cmd.CommandType CommandType.StoredProcedure; cmd.CommandText pkg_order.sp_create_order; // 带包名不能写成 call pkg_order.sp_create_order()如果你写成call pkg_order.sp_create_order()或者带begin ... end;Oracle 会把它当成匿名 PL/SQL 块CommandType.StoredProcedure就形同虚设。另外Oracle 默认对象名是大写如果你建过程时用了引号强制小写那CommandText也必须带引号匹配。3.3 参数绑定名称、方向、类型三要素Oracle 不靠函数签名推断参数OracleParameter的ParameterName必须和存储过程中定义的参数名完全一致区分大小写哪怕只差一个下划线也会绑定失败。假设 PL/SQL 端定义如下CREATE OR REPLACE PACKAGE BODY pkg_order AS PROCEDURE sp_create_order( p_user_id IN NUMBER, p_amount IN NUMBER, p_remark IN VARCHAR2, p_order_id OUT NUMBER, p_cur OUT SYS_REFCURSOR ) AS BEGIN INSERT INTO orders(id, user_id, amount, remark) VALUES (seq_order.NEXTVAL, p_user_id, p_amount, p_remark) RETURNING id INTO p_order_id; OPEN p_cur FOR SELECT * FROM orders WHERE id p_order_id; END; END;对应的 C# 参数配置var pUserId new OracleParameter(p_user_id, OracleDbType.Int32, ParameterDirection.Input); pUserId.Value 1001; cmd.Parameters.Add(pUserId); var pAmount new OracleParameter(p_amount, OracleDbType.Decimal, ParameterDirection.Input); pAmount.Value 299.50m; cmd.Parameters.Add(pAmount); var pRemark new OracleParameter(p_remark, OracleDbType.Varchar2, ParameterDirection.Input); pRemark.Value 来自C#的订单; cmd.Parameters.Add(pRemark); var pOrderId new OracleParameter(p_order_id, OracleDbType.Int32, ParameterDirection.Output); cmd.Parameters.Add(pOrderId); var pCur new OracleParameter(p_cur, OracleDbType.RefCursor, ParameterDirection.Output); cmd.Parameters.Add(pCur);几个关键点OracleDbType要尽量选精确类型Varchar2对应VARCHAR2Int32对应NUMBER(10)别全用OracleDbType.Decimal。对于 REF CURSOR必须用OracleDbType.RefCursor且不能设Value。如果存储过程定义了默认值参数C# 仍需显式添加该参数并设Value DBNull.Value否则 Oracle 认为“未提供”可能触发ORA-01008。3.4 执行与读取 REF CURSORREF CURSOR 不能像普通输出参数那样直接取值它本质是个游标句柄得用OracleDataAdapter或ExecuteReader()拿结果集。using var reader cmd.ExecuteReader(); if (reader.Read()) { Console.WriteLine($订单ID: {reader[id]}, 金额: {reader[amount]}); } reader.Close(); int newOrderId Convert.ToInt32(pOrderId.Value); Console.WriteLine($新订单ID: {newOrderId});如果你用ExecuteNonQuery()REF CURSOR 的结果是拿不到的。另外ExecuteReader()返回的 reader 要先读完再取 OUT 参数值顺序反了可能拿不到。3.5 事务处理显式 BeginTransactionOracle 的 DML 不会自动提交如果你在一个业务方法里调多个存储过程建议显式开事务。using var tran conn.BeginTransaction(); cmd.Transaction tran; try { cmd.ExecuteNonQuery(); tran.Commit(); } catch { tran.Rollback(); throw; }注意OracleCommand的Transaction属性必须赋值否则事务不生效。如果你用的是OracleDataAdapter它内部会自己管理连接事务场景下要小心。4. 验证请求跑通一次完整调用把上面的代码拼起来写一个控制台验证程序。先确认数据库里有对应的包和过程然后执行static void Main() { string connStr Data Sourcelocalhost:1521/ORCLPDB1;User Idapp_user;Passwordyour_pwd;UnicodeTrue;; using var conn new OracleConnection(connStr); conn.Open(); using var cmd conn.CreateCommand(); cmd.CommandType CommandType.StoredProcedure; cmd.CommandText pkg_order.sp_create_order; cmd.Parameters.Add(new OracleParameter(p_user_id, OracleDbType.Int32) { Value 1001, Direction ParameterDirection.Input }); cmd.Parameters.Add(new OracleParameter(p_amount, OracleDbType.Decimal) { Value 299.50m, Direction ParameterDirection.Input }); cmd.Parameters.Add(new OracleParameter(p_remark, OracleDbType.Varchar2) { Value 验证调用, Direction ParameterDirection.Input }); cmd.Parameters.Add(new OracleParameter(p_order_id, OracleDbType.Int32) { Direction ParameterDirection.Output }); cmd.Parameters.Add(new OracleParameter(p_cur, OracleDbType.RefCursor) { Direction ParameterDirection.Output }); using var reader cmd.ExecuteReader(); while (reader.Read()) { Console.WriteLine($返回行: id{reader[id]}, amount{reader[amount]}); } reader.Close(); Console.WriteLine($OUT 订单ID {cmd.Parameters[p_order_id].Value}); }成功的话控制台会打印出刚插入的订单行和新生成的订单 ID。如果p_order_id是DBNull检查RETURNING INTO是否真的写入了如果 reader 没有行检查 REF CURSOR 是否在 PL/SQL 里正确 OPEN。5. 本篇常见错排查5.1 ORA-06502类型不匹配多半是 C# 传intPL/SQL 期望NUMBER(1)或者传了string但目标列是NUMBER。解决办法是把OracleDbType调精确比如NUMBER(1)用OracleDbType.ByteNUMBER(10)用OracleDbType.Int32。别全用Decimal糊弄。5.2 ORA-01008未绑定变量本质是参数名拼错或漏加OracleParameter。Oracle 对参数名大小写敏感p_user_id和P_USER_ID是两个东西。建议直接从 PL/SQL 定义里复制参数名别手敲。5.3 无报错但存储过程没执行先检查CommandText是不是带了call或begin/end。再检查CommandType是不是真的设成了StoredProcedure。最后确认连接字符串有没有UnicodeTrue虽然它不直接导致不执行但会影响参数传输。5.4 取 OUT 值时崩掉或乱码如果 OUT 参数是VARCHAR2且包含中文连接字符串没加UnicodeTrue时错误往往不直接报在执行阶段而是在取 OUT 值时崩掉。加上UnicodeTrue再试。5.5 REF CURSOR 读不到数据确认OracleDbType.RefCursor且没有设Value。确认用的是ExecuteReader()而不是ExecuteNonQuery()。确认 PL/SQL 里确实OPEN ... FOR了。6. 把 AI 辅助配置接进你的工作流存储过程调用的排查往往需要反复查文档、对比参数类型、生成测试 PL/SQL 块。如果你想让 AI 辅助这个过程可以用 TaoToken 的 API Key 统一管理通道。创建 Key 的入口在https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。对于长期做 C# 编码和 Agent 辅助的场景Coding Plan 会更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。如果你只是想先验证模型对话效果模型对话入口在https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。我自己的习惯是把连接字符串模板、参数绑定骨架和常见错误码整理成一个提示词模板通过 TaoToken 的通道发给模型让它帮我检查参数名和类型是否匹配。这样比手动翻文档快很多尤其是面对几十个参数的包过程时。最后提醒一句AI 生成的 PL/SQL 块一定要在测试库先跑别直接上生产。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/11/3 7:07:39

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/11/2 5:53:30

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/11/2 5:53:30

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/11/2 5:53:28

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/11/2 5:53:27

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/11/2 5:53:27

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉