【问题标题】:Using ODP.NET to get a RECORD from PL/SQL function, without touching PL/SQL code使用 ODP.NET 从 PL/SQL 函数中获取 RECORD,无需接触 PL/SQL 代码
【发布时间】:2013-06-05 13:27:33
【问题描述】:

标题非常不言自明:从一个 C# 应用程序,使用 ODP.NET,我试图调用一个 PL/SQL 函数,它返回的不是一个简单的值,而是一个记录。

不幸的是,我无权添加或更改 PL/SQL 代码,因此尝试将函数包装在返回不同类型的另一个函数中对我来说不是一个选项。

这是一个简化的例子……

PL/SQL:

CREATE OR REPLACE PACKAGE FOO_PACKAGE AS

    TYPE FOO_RECORD IS RECORD (
        BAR VARCHAR2(50),
        BAZ VARCHAR2(50)
    );

    FUNCTION FOO_FUNCTION RETURN FOO_RECORD;

END;
/

CREATE OR REPLACE PACKAGE BODY FOO_PACKAGE AS

    FUNCTION FOO_FUNCTION RETURN FOO_RECORD AS
        R FOO_RECORD;
    BEGIN
        R.BAR := 'Hello bar!';
        R.BAZ := 'Hello baz!';
        RETURN R;
    END;

END;
/

C#:

我尝试的第一件事是最直接的方法,但是我很茫然如何绑定返回参数...

using (var conn = new OracleConnection(connection_string)) {
    conn.Open();
    using (var tran = conn.BeginTransaction()) {
        using (var cmd = conn.CreateCommand()) {
            cmd.CommandText = "FOO_PACKAGE.FOO_FUNCTION";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add(
                null,
                /* What to use here? */,
                ParameterDirection.ReturnValue
            );
            cmd.ExecuteNonQuery();
        }
    }
}

我也尝试过一些“迂回”的方法,但都抛出异常:

cmd.CommandText = "SELECT * FROM FOO_PACKAGE.FOO_FUNCTION";
cmd.ExecuteReader(); // ORA-00942: table or view does not exist

cmd.CommandText = "SELECT FOO_PACKAGE.FOO_FUNCTION FROM DUAL";
cmd.ExecuteReader(); // ORA-00902: invalid datatype

cmd.CommandText = "SELECT BAR, BAZ FROM (SELECT FOO_PACKAGE.FOO_FUNCTION FROM DUAL)";
cmd.ExecuteReader(); // ORA-00904: "BAZ": invalid identifier

【问题讨论】:

    标签: oracle record odp.net


    【解决方案1】:

    您需要anonymous PL/SQL block 将函数结果转换为另一种表示形式:

    declare
      vFooRes FOO_PACKAGE.FOO_RECORD;
      vRes sys_refcursor;
    begin
      vFooRes := FOO_PACKAGE.FOO_FUNCTION;
      open vRes for select vFooRes.BAR, vFooRes.BAZ from dual;
      --:result := vRes;
    end;
    

    SQLfiddle

    并执行它而不是调用存储过程:

    cmd.CommandText = "declare\n" +
                      "  vFooRes FOO_PACKAGE.FOO_RECORD;\n" + 
                      "begin\n" + 
                      "  vFooRes := FOO_PACKAGE.FOO_FUNCTION;\n" + 
                      "  open :result for select vFooRes.BAR, vFooRes.BAZ from dual;\n" + 
                      "end;";
    
    OracleParameter p = cmd.Parameters.Add(
                          "result",
                           OracleDbType.RefCursor,
                           DBNull.Value,
                           ParameterDirection.Output
                        );
    
    cmd.ExecuteNonQuery();
    

    执行cmd 后,光标在result 参数中,可用于填充数据集:

    var adapter = new OracleDataAdapter(cmd);
    var data = new DataSet("FooDataSet");
    adapter.Fill(data, "result", (OracleRefCursor)(p.Value));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-31
      • 1970-01-01
      • 1970-01-01
      • 2013-05-06
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      • 2010-10-12
      相关资源
      最近更新 更多