从 C#/.Net 在 oracle 中创建和编译“动态”存储过程

Posted

技术标签:

【中文标题】从 C#/.Net 在 oracle 中创建和编译“动态”存储过程【英文标题】:Create and compile "on the fly" stored procedure in oracle from C#/.Net 【发布时间】:2011-05-14 03:13:01 【问题描述】:

我知道有人问过这个问题before,但这些解决方案似乎不适用于我。

我目前正在尝试这样做:

    为 oracle 构建“CREATE PROCEDURE”脚本字符串 使用企业库 5.0 创建 SQL 命令并将此字符串作为参数传递 将过程保存在 oracle 数据库中

到目前为止,第 3 点似乎有效,如果我打开 SQL Developer 并展开过程树列表,那么我实际上可以看到该过程,但带有红十字圆圈,这意味着它虽然运行相同的代码,但它存在编译器错误,这非常小,在 SQL Developer 查询窗口中可以正常工作并编译它。我不确定 SQL Developer 在幕后做了什么,因为运行该“CREATE PROCEDURE”脚本不会引发任何错误,然后我可以查看并执行该过程,但不能从 C# 执行它。

我在开头的链接中读到我应该调用IDBCommand.Prepare(),但该方法仅在您的 SQLCommand.CommandType 类型为 StoredProcedure 时才相关,因为我实际上并没有调用过程而是运行纯sql to CREATE the procedure 然后这行不通,不过,我只是为了测试,创建了一个新命令,我分配给 StoredProcedure 然后在该命令上调用 Prepare() 方法,最后是 ExecuteNonQuery() 方法这会引发对象(存储过程)不可用的异常,这是有道理的,因为它尚未编译...

所以,我想知道是否有人真的知道如何创建一个过程并从 C# 编译它,我们目前正在使用企业库,但我不介意直接向 oracle 提供者“硬编码”一些东西,只要它可以工作.

顺便说一句,在告诉我从代码创建过程是一种不好的做法之前,我告诉你,不幸的是,这是客户的项目,我们没有做出任何决定,实际上我们正在尝试将东西从 SQL Server 迁移到甲骨文。

【问题讨论】:

好吧,事实证明,出于某种原因,如果您愿意,在具有 CREATE PROCEDURE 命令的字符串上使用回车符 (CR) 或换行符会导致此问题,所以,不知何故,这被预言机错误地解释了,谁知道是什么原因。无论如何,我“有点”通过执行 mysqlStr.Replace(System.Environment.NewLine, string.Empty) 解决了它,这样命令进入了由 10g Express 正确解析的单行。 【参考方案1】:

我有点生疏,目前没有 Oracle 访问权限,但我想我知道您的要求。您想使用 ADO.NET OracleCommand 类和 Oracle EXECUTE IMMEDIATE 语句。像这样的:

        OracleConnection conn = new OracleConnection("Data Source=something; user id=something; Password=something;");
        conn.Open();
        OracleCommand command = new OracleCommand();
        command.CommandType = CommandType.Text;
        command.CommandText = "execute immediate 'create or replace procedure [...you know this part...]' ";
        command.Connection = conn;
        command.ExecuteNonQuery();
        conn.Close();
    

应该可以。但请注意,我一直使用ODP.NET(Oracle 自己的数据提供程序)而不是库存的 ADO.NET,所以如果您只是使用库存库,可能会有一些细微差别。

正如 Pete 所建议的,您也可以使用动态 SQL 来达到同样的效果。您将整个 CREATE PROCEDURE 语句作为参数传递给现有存储过程,然后该存储过程为您调用 EXECUTE IMMEDIATE。但是,我不相信您必须那样做。如果您想保持最小化,上述方法应该可以工作。

另一件事。我不知道为什么会发生这种情况,但是如果 Oracle 告诉您该过程无效,即使您知道它很好,请尝试执行

EXECUTE IMMEDIATE ALTER PROCEDURE schemaname.procedurename COMPILE;

我经常发现 Oracle 在不必要地使对象无效方面有点脆弱。

【讨论】:

"EXECUTE IMMEDIATE CREATE OR REPLACE..." 不行,我确实在使用oracle自己的提供者DLL ODAC 对不起,您需要将正在执行的命令放在单引号中。固定。【参考方案2】:

如果要在 SQL Server 或 Oracle 中动态执行 DDL 语句,则必须将在 C# 中创建的 DDL 传递给 Oracle 中的过程,然后使用 EXECUTE IMMEDIATE 将字符串作为命令运行并创建过程。

来自 Oracle 的This page 提到,如果“您要执行 DDL 语句和纯静态 SQL 程序不支持的其他 SQL 语句”,则必须使用动态 sql。

希望对你有帮助。

【讨论】:

我认为这是正确的答案,接受的答案对我不起作用,确实如此。我无法使用 ODP.NET 创建存储过程,除非我按照 Pete 的建议做,+1。【参考方案3】:

最后一个字符是什么?

Oracle 的原始 SQL*Plus 使用斜线字符来执行当前命令。许多 IDE 要么使用相同的斜线,要么将斜杠解释为不是过程/包的一部分

因此,如果您的“CREATE ...”字符串的末尾有一个斜杠(在新行上),那么这将是一个错误。但是,如果由 IDE 加载并重新编译,IDE 可能会为您删除它。

在 C# 加载后检查 USER_ERRORS 并查看该程序单元是否报告了任何错误。

【讨论】:

末尾没有斜线字符。

以上是关于从 C#/.Net 在 oracle 中创建和编译“动态”存储过程的主要内容,如果未能解决你的问题,请参考以下文章

Oracle Sql Developer如何在Oracle中创建和设置角色?

在 R 中创建和组合两个图 - xy 线图和条形链图

在 SQLite.Net-PCL 中创建和使用具有复合主键的表

如何在 .Net 中创建和解析标签、长度、值 (TLV) 并在 Base64 中对其进行编码

如何在 C++ 或 C 中创建和编写索引 png 图像

在C和/或C ++中创建和管理内存中的字节缓冲区,可以根据需要自动调整大小