2

次の表があるとします。

create table egyen (
  id number not null, 
  tajszam varchar2(9),
  nev varchar2(10),
  primary key(id)
);

そして次のパッケージ:

create or replace package pck_egyen is
  type egyentab is table of egyen%rowtype;
  procedure list(ret$ out egyentab);
end pck_egyen;
/
create or replace package body pck_egyen is
  procedure list(ret$ out egyentab) is
  begin
    ret$ := egyentab();
    for rec in (select * from egyen) loop
      ret$.extend;
      ret$(ret$.count) := rec;
    end loop;
  end;
end pck_egyen;
/

誰かが、ODP.NET 11gを使用して、テーブル、タイプ、またはパッケージを変更せずに、このストアドプロシージャを呼び出すことができる、動作する.NETコードを提供できますか?pck_egyen.egyentabタイプをサポートするようにOracleParameterを設定する方法がわかりません...

これまでUDTを使用したことがないので、試してみましたが、パッケージに埋め込まれているタイプが認識されません。グローバルタイプは%rowtypeをサポートしていません。私は立ち往生しているようです。もともと私はrefカーソルを返したかったのですが、チャームのように機能しますが、dblinkを介しては機能しません。愚かな制限が多すぎます。

4

3 に答える 3

3

これは興味深い問題です。特に、データを消費するために.NETと、dblink間でストアドプロシージャの両方を使用する必要があるためです。dblink間でカーソルを使用しないという制限により、pl / sqlテーブルが作成されましたが、.NETではこれらを簡単に使用できません(グローバルオブジェクトの設定と保​​守の手間をかけずに)。

そこで、refカーソル関数とプロシージャの両方を出力テーブルパラメータで使用することを提案します。.NETからrefカーソル関数を簡単に呼び出すことができ(dblink全体を選択する必要がない場合)、dblinkデータベースの作業には、対応する手順を使用します。例えば:

create table test1 (
    col1 number,
    col2 varchar2(10),
    col3 date default sysdate not null
);
insert into test1(col1,col2) values (1,'A');
insert into test1(col1,col2) values (1,'X');
insert into test1(col1,col2) values (2,'B');

commit;

CREATE OR REPLACE package TEST_PKG as
  type t_test1_tab is table of test1%rowtype;
  -- weak ref cursor
  function get_test1_cur (i_num in number) return sys_refcursor;
  -- uses rowtype for table
  procedure get_test1_tab(i_num in number, o_tab out t_test1_tab);
end;


CREATE OR REPLACE package body TEST_PKG as
  function get_test1_cur (i_num in number) return sys_refcursor is
    l_cur sys_refcursor;
  begin
    open l_cur for select * from test1 where col1=i_num;
    return l_cur;
  end;

  procedure get_test1_tab(i_num in number, o_tab out t_test1_tab) is
    l_rec test1%rowtype;
    l_tab t_test1_tab := t_test1_tab();
    l_cur sys_refcursor;
  begin
    l_cur := get_test1_cur(i_num);
    loop
      fetch l_cur into l_rec;
      exit when l_cur%notfound;
      l_tab.extend;
      l_tab(l_tab.last) := l_rec;
    end loop;
    close l_cur;
    o_tab := l_tab;
  end;

end;

必要なロジックをrefカーソル関数内に配置します。このプロシージャは、関数を呼び出してテーブルを作成するだけです(rowtypeを使用)。

dblinks間でのdb呼び出しの手順を使用します。

declare
  l_tab test_pkg.t_test1_tab@dblinkA;
begin
  test_pkg.get_test1_tab@dblinkA(1, l_tab);
  -- show count
  dbms_output.put_line('Table has ' || l_tab.count || ' rows.');
end;

odp.net呼び出しにこの関数を使用します。例(コードスニペット):

OracleConnection con = new OracleConnection(connStr);

// create the command object and set attributes
OracleCommand cmd = new OracleCommand("test_pkg.get_test1_cur", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.BindByName = false;

// create parameter object for the cursor
OracleParameter p_refcursor = new OracleParameter();
// create any input parameters to the function
OracleParameter p_num = new OracleParameter();

p_refcursor.OracleDbType = OracleDbType.RefCursor;
p_refcursor.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(p_refcursor);

// add any input parameters
p_num.OracleDbType = OracleDbType.Int32;
p_num.Direction = ParameterDirection.Input;
p_num.Value = 1;
cmd.Parameters.Add(p_num);

// create a data adapter to use with the data set
OracleDataAdapter da = new OracleDataAdapter(cmd);

// create the data set
DataSet ds = new DataSet();

// fill the data set
da.Fill(ds);

このアプローチは、行タイプを使用しているだけでなく、プロシージャが関数を呼び出すだけなので、保守が簡単なはずです。

于 2013-02-13T14:43:41.947 に答える
2

1つのアプローチは、PL/SQLを使用して表オブジェクトのデータを列ごとに1つずつPL/SQL連想配列に読み込み、ODP.NETを使用してこれらを読み込むことです。

    private const string PlSqlBlock = @"
        DECLARE
          l_egyen_tab  pck_egyen.egyentab;
        BEGIN
          pck_egyen.list(l_egyen_tab);
          FOR i IN 1..l_egyen_tab.COUNT
          LOOP
            :ids(i) := l_egyen_tab(i).id;
            :tajszams(i) := l_egyen_tab(i).tajszam;
            :nevs(i) := l_egyen_tab(i).nev;
          END LOOP;
        END;";

    public static void ListEgyenTable(OracleConnection con)
    {
        using (var cmd = new OracleCommand(PlSqlBlock, con))
        {
            OracleParameter idParam = cmd.Parameters.Add("ids", OracleDbType.Decimal);
            OracleParameter tajszamParam = cmd.Parameters.Add("tajszams", OracleDbType.Varchar2);
            OracleParameter nevParam = cmd.Parameters.Add("nevs", OracleDbType.Varchar2);

            int arraySize = 1000;
            int[] varcharArrayBindSize = Enumerable.Repeat(4000, arraySize).ToArray();

            foreach (OracleParameter param in cmd.Parameters)
            {
                param.Direction = ParameterDirection.Output;
                param.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
                param.Size = arraySize;
                if (param.OracleDbType == OracleDbType.Varchar2)
                {
                    param.ArrayBindSize = varcharArrayBindSize;
                }
            }

            cmd.ExecuteNonQuery();

            if (idParam.Value is OracleDecimal[] && tajszamParam.Value is OracleString[] && nevParam.Value is OracleString[])
            {
                List<decimal> ids = (idParam.Value as OracleDecimal[]).Select(dec => dec.Value).ToList();
                List<string> tajszams = (tajszamParam.Value as OracleString[]).Select(str => str.Value).ToList();
                List<string> nevs = (nevParam.Value as OracleString[]).Select(str => str.Value).ToList();

                for (int i = 0; i < ids.Count; ++i)
                {
                    Console.WriteLine("Got id {0}, tajszam {1}, nev {2}", ids[i], tajszams[i], nevs[i]);
                }
            }
            else
            {
                Console.WriteLine("Sorry, returned data not as expected :(");
            }
        }
    }

ここでの唯一の問題はですarraySize。この値は、少なくともストアド・プロシージャから返される行数である必要があります。値が小さすぎると、ORA-06513'PL / SQL:PL/SQL表の索引がホスト言語の範囲外になります。アレイのエラー。

テーブルとパッケージを作成し、次のテストデータをテーブルに挿入しました。

SQL> select * from egyen;

        ID TAJSZAM   NEV
---------- --------- ----------
         1 abc       defg
         2 def       mnop
         3 ghi       qrstu
         4 jkl       vwxyz

上記のC#コードを実行すると、次の出力が得られました。

ID 1、tajszam abc、nevdefgを取得しました
ID 2、tajszam def、nevmnopを取得しました
ID 3、tajszam ghi、nevqrstuを取得しました
ID 4、tajszam jkl、nevvwxyzを取得しました
于 2013-02-10T10:57:10.973 に答える
0

次のようなものを試してください

OracleCommand cmd = new OracleCommand();
cmd.CommandText = "pck_egyen.list";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.Add("ret$", OracleDbType.RefCursor, DBNull.Value, ParameterDirection.Output);

cmd.ExecuteNonQuery();

// Read the result set
OracleRefCursor orarefcur = (OracleRefCursor) cmd.Parameters[0].Value;
OracleDataReader dr = orarefcur.GetDataReader();    
while (dr.Read())
{
    System.Console.WriteLine(dr["tajszam"]);
}
于 2013-02-09T10:44:10.420 に答える