我不是第一个遇到这些问题的人,我会在下面列出一些引用帖子,但我仍在寻找合适的解决方案。
我需要从 C# Web 服务调用存储过程(Oracle 10g 数据库)。 Web 服务器安装了 Oracle 9i 客户端,我使用的是 Microsoft 的 System.Data.OracleClient
。
该过程将 XML 作为 CLOB。当 XML 超过 4000 字节(这在正常用例中很可能)时,我偶然发现了以下错误:
ORA-01460 - unimplemented or unreasonable conversion requested
此外,我发现了一个很有前途的解决方法,它不直接从 C# 调用存储过程,而是定义了一段匿名 PL/SQL 代码。此代码作为 OracleCommand 运行。 XML 作为字符串文字嵌入,过程调用是从该段代码中完成的:
private const string LoadXml =
"DECLARE " +
" MyXML CLOB; " +
" iStatus INTEGER; " +
" sErrMessage VARCHAR2(2000); " +
"BEGIN " +
" MyXML := '{0}'; " +
" iStatus := LoadXML(MyXML, sErrMessage); " +
" DBMS_OUTPUT.ENABLE(buffer_size => NULL); " +
" DBMS_OUTPUT.PUT_LINE(iStatus || ',' || sErrMessage); " +
"END;";
OracleCommand oraCommand = new OracleCommand(
string.Format(LoadXml, xml), oraConnection);
oraCommand.ExecuteNonQuery();
不幸的是,这种方法现在一旦 XML 超过 32 KB 左右就会失败,这在我的应用程序中仍然很有可能。这次错误源于 PL/SQL 编译器,它说:
ORA-06550: line1, column 87: PLS-00172: string literal too long
经过一些研究,我得出结论,用第二种方法解决问题根本不可行。
根据上述帖子,我有以下两个选择。
- Switch to ODP.NET (因为它应该是 Microsoft 已弃用的数据库客户端中的错误)
- Insert the CLOB into a table并从那里读取存储过程
(The first post 说有些客户端有问题,但我的 (9i) 不在上述 10g/11g 版本范围内。)
您能否确认这是仅剩的两个选项?或者有其他方法可以帮助我吗?
澄清一下:XML不会最终保存在任何表中,但它是由存储过程处理的,该存储过程根据 XML 内容在某些表中插入一些记录。
我对这两个选项的考虑:
- 切换到 ODP.NET 很困难,因为我必须将它安装在我目前没有系统访问权限的 Web 服务器上,并且因为我们可能还想在客户端上部署这段代码,所以每个客户端必须在部署过程中安装 ODP.NET。
- 绕过表格使客户端代码变得相当复杂,并且在数据库适应/扩展 PL/SQL 例程方面也需要付出相当大的努力。
最佳答案
我发现是另一种解决问题的方法!我的同事救了我一整天,指着我this blog ,它说:
Set the parameter value when BeginTransaction has already been called on the DbConnection.
可以更简单吗?该博客与 Oracle.DataAccess
相关,但它同样适用于 System.Data.OracleClient
。
在实践中这意味着:
varcmd = new OracleCommand("LoadXML", _oracleConnection);
cmd.CommandType = CommandType.StoredProcedure;
var xmlParam = new OracleParameter("XMLFile", OracleType.Clob);
cmd.Parameters.Add(xmlParam);
// DO NOT assign the parameter value yet in this place
cmd.Transaction = _oracleConnection.BeginTransaction();
try
{
// Assign value here, AFTER starting the TX
xmlParam.Value = xmlWithWayMoreThan4000Characters;
cmd.ExecuteNonQuery();
cmd.Transaction.Commit();
}
catch (OracleException)
{
cmd.Transaction.Rollback();
}
关于c# - 使用大型 CLOB 从 C# 调用存储过程时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3557995/