c# - 使用大型 CLOB 从 C# 调用存储过程时出现问题

标签 c# oracle stored-procedures clob system.data.oracleclient

我不是第一个遇到这些问题的人,我会在下面列出一些引用帖子,但我仍在寻找合适的解决方案。

我需要从 C# Web 服务调用存储过程(Oracle 10g 数据库)。 Web 服务器安装了 Oracle 9i 客户端,我使用的是 Microsoft 的 System.Data.OracleClient

该过程将 XML 作为 CLOB。当 XML 超过 4000 字节(这在正常用例中很可能)时,我偶然发现了以下错误:

ORA-01460 - unimplemented or unreasonable conversion requested

我找到了 this , thisthis发布。

此外,我发现了一个很有前途的解决方法,它不直接从 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

经过一些研究,我得出结论,用第二种方法解决问题根本不可行。

根据上述帖子,我有以下两个选择。

(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/

相关文章:

java - 从 Oracle 中返回表的函数中选择的其他方法

具有可变方法、查询和限制的 mySQL 存储过程

mysql - mysql存储过程中的参数

spring - 我如何使用带有 jpa 的 spring 调用存储过程

c# - 十进制 DbParameter 的精度问题

c# - asp.net 添加新字体

sql - Sql 左连接 oracle 上的标识符无效

javascript - 图表js,动态加载数据

javascript - 如何在 Controller 中保留 html 中的变量?

vb.net - 如何检查 DataReader 值是否为空?