通过 .NET 使用 PL/SQL 集合类型参数调用 Oracle 过程 [英] Calling an Oracle procedure with a PL/SQL collection type parameter via .NET

查看:22
本文介绍了通过 .NET 使用 PL/SQL 集合类型参数调用 Oracle 过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过 .NET 调用 Oracle 存储过程.通常这不是问题,但是这个存储过程包含一个 PL/SQL 集合类型的参数:

I'm trying to call an Oracle stored procedure via .NET. Normally this isn't a problem, but this stored procedure contains a parameter that is a PL/SQL collection type:

create or replace type test_type as table of number;
PROCEDURE TEST1 (pvTest IN test_type);

这是我的 C# 代码:

This is my C# code:

var receiverIds = new decimal[] { 683552, 683553, 683572, 683573, 683592, 683593, 683594, 683612 };
var receiversList = new OracleParameter("pvTest", OracleDbType.Decimal, ParameterDirection.Input);
receiversList.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
receiversList.Size = receiverIds.Length;
receiversList.Value = receiverIds;

using (var oracleCommand = new OracleCommand())
{
    oracleCommand.Connection = this.oracleConnection;
    oracleCommand.CommandText = "test_package.TEST1";
    oracleCommand.BindByName = true;

    oracleCommand.Parameters.Add(parameter);

    oracleCommand.CommandType = CommandType.StoredProcedure;

    oracleCommand.ExecuteNonQuery();
}

执行此操作时,我收到ORA-06550:错误的参数数量或类型"错误.在本主题中:ORA-06550:错误的参数数量或类型错误 |使用表类型 IN 参数调用 Oracle 过程 我发现我应该在包中声明我的自定义类型.

When I execute this, I get the "ORA-06550: Wrong number or type of arguments" error. In this topic: ORA-06550: Wrong number or type of arguments error | Calling Oracle Procedure with Table type IN parameter I found that I should declare my custom type inside my package.

所以我创建了一个如下所示的测试包:

So I created a test package that looks like this:

CREATE OR REPLACE PACKAGE test_package_gkeu IS
    TYPE test_type IS TABLE OF NUMBER;

    PROCEDURE TEST1 (pvTest IN test_type);
END test_package_gkeu;
/

CREATE OR REPLACE PACKAGE BODY test_package_gkeu IS
    PROCEDURE TEST1 (pvTest IN test_type) IS
    BEGIN
      null;
    END TEST1;
END test_package_gkeu;
/

然而,这仍然产生了完全相同的错误.经过更多的搜索和尝试后,我发现我需要将INDEX BY BINARY_INTEGER"添加到test_type"并且可以正常工作,这样我就可以毫无错误地调用我的程序.

However, this still produced the exact same error. After some more searching and trying I found that I need to add "INDEX BY BINARY_INTEGER" to "test_type" and that works, with this I can call my procedure without errors.

然后我开始将原始过程中的 SQL 查询添加到这个测试包中:

Then I started adding the SQL query from the original procedure to this test package:

select *
from receiver r
where r.receiverid in (select /*+cardinality(t 5)*/ *
from table(cast((pvTest) as test_type)) t
where rownum >= 0);

但是现在我不能再构建我的包了.我在 StackOverflow 上发现了以下内容(PlSQL Invalid data type even after cast why):

But now I cannot build my package anymore. I found the following on StackOverflow (PlSQL Invalid data type even after casting why):

包中定义的 PL/SQL 类型对 SQL 语句不可见:它们是纯 PLSQL 构造,SQL 语言无法直接访问它们.

PL/SQL types defined in package are invisible to SQL statements: they are pure PLSQL constructs and the SQL language can't access them directly.

还有 其他地方我发现:

不能全局声明表索引;以下构造生成 PLS-00355:在此上下文中不允许使用 pl/sql 表.

Index by tables cannot be declared globally; the following construct generates a PLS-00355: use of pl/sql table not allowed in this context.

所以我在这里进退两难.如果自定义类型没有INDEX BY",我将无法调用该过程,当我在包中声明它时,我无法在查询中使用此类型,并且由于索引".

So I'm in a dilemma here. I can't call the procedure if the custom type doesn't have an "INDEX BY", I can't use this type in a query when I declare it in the package and I can't declare it globally due to the "INDEX BY".

谁能帮帮我?我想我需要找到一种在类型没有INDEX BY"时调用过程的方法,但我已经尝试了所有我能想到或找到的方法.

Could anyone help me out? I guess I need to find a way to call the procedure when the type doesn't have an "INDEX BY", but I've tried everything I could think of or find.

ps.我正在使用 .NET 4.5 和 Oracle.ManagedDataAccess v 4.121.1.0不幸的是,我们的 Oracle 数据库仍然是 10g (10.2.0.4.0).

ps. I'm using .NET 4.5 and Oracle.ManagedDataAccess v 4.121.1.0 and our Oracle database is, unfortunately, still 10g (10.2.0.4.0).

推荐答案

通过 ODP.NET 的过程调用仅支持关联数组,即带有 INDEX BY ...,不支持嵌套表.

Procedure call via ODP.NET supports only Associative arrays, i.e. with INDEX BY ..., Nested Tables are not supported.

一种解决方案是在您的 Orale 程序中转换:

One solution is to convert in in your Orale procedure:

CREATE OR REPLACE PACKAGE test_package_gkeu IS

    TYPE test_type IS TABLE OF NUMBER;    
    TYPE test_type_associative IS TABLE OF NUMBER INDEX BY INTEGER;

PROCEDURE TEST1 (pvTest IN test_type_associative ) IS

v test_type := test_type();
BEGIN
   v.Extend(pvTest.COUNT);
   for i in pvTest.First..pvTest.Last loop
       v(i) := pvTest(i)
   end loop;

select *
into ...
from receiver r
where r.receiverid MEMBER OF (v);

END;

对于 DML 语句,还要考虑:

For DML statements consider also this:

FORALL i IN INDICES OF pvTest 
    INSERT INTO MY_TABLE (COL_A)
    VALUES (pvTest(i));

or 

FORALL i IN INDICES OF pvTest 
    DELETE FROM receiver 
    WHERE receiverid  = pvTest(i);

这篇关于通过 .NET 使用 PL/SQL 集合类型参数调用 Oracle 过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆