2013-06-05 43 views
3

標題不言而喻:從C#應用程序使用ODP.NET,我試圖調用PL/SQL函數返回的不是一個簡單的值,而是一條記錄。使用ODP.NET從PL/SQL函數中獲取RECORD,而不接觸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 

回答

7

您需要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參數光標可用於填充數據集:

adapter = New OracleDataAdapter(cmd) 
data = New DataSet("FooDataSet") 
adapter.Fill(data, "result", (OracleRefCursor)(cmd.Parameters["result"].Value)); 
+0

大,非常感謝!我希望我可以不止一次地upvote :) –

+0

不客氣。一次就夠了:) – ThinkJet

+0

這真是太棒了 –