- PR -

ODP.NETでIN引数に配列を持つストアドファンクションのパラメータセットについて

1
投稿者投稿内容
K-Kei
会議室デビュー日: 2004/09/01
投稿数: 7
投稿日時: 2008-02-14 20:12
お世話になります。
既に既出のスレッドがあることを確認した上での質問なのですが
OracleDBにIN引数として配列を持つストアドファンクションを作成の上、
VisualC#.NET+ODP.NETでファンクション呼び出しを行おうとしているのですが
配列引数の設定方法がまったくわかりません。oo4oではAddTableなるものが
あることは存じているのですが・・・

環境ですが、
OracleClient 9.2.0.1(但しPSR9.2.0.4のパッチ当て済み)
ODP.NET 9.2.0.4
です。

下記にストアドファンクションの定義部とパッケージ部をそれぞれ載せます。
-------------- 定義部
CREATE OR REPLACE PACKAGE TEST.PKG_TEST AS
TYPE value_table is table of number index by pls_integer;
TYPE str_table is table of varchar2(10) index by pls_integer;

FUNCTION F1(
vals in value_table
) RETURN number;

FUNCTION F2(
strs in str_table
) RETURN number;

END PKG_TEST;
/

------------------------- パッケージ部
CREATE OR REPLACE PACKAGE BODY TEST.PKG_TEST AS

FUNCTION F1
(
vals in value_table
)
RETURN number
IS
BEGIN
for i in vals.first..vals.last loop
INSERT INTO TEMP(A, WRITE_TIME) values ( vals(i), sysdate);
end loop;

commit;
return 0;

END F1;

OTNのサイトのマニュアルは既に閲覧済みです。
http://otndnld.oracle.co.jp/tech/windows/odpnet/howto/04_arraybind/content.html
ここのサンプルを参考にコードを組んでみたのですが
ストアドファンクションの例ではなく、動作しませんでした。

また、別な例として下記URLの記事を参考にしてコードを組んでみたのですが
やはり動きませんでした。
http://otndnld.oracle.co.jp/document/products/oracle10g/102/windows/B31247-01/featOraCommand.htm#BABBDHBB
http://www.atmarkit.co.jp/fdb/rensai/odpdotnet03/odpdotnet03_3.html
いずれもストアドプロシージャを対象としていて
ストアドファンクションの例ではありませんでした。

ODP.NETでストアドファンクションに配列パラメータを
渡す方法について、どなたかご教授ください。
作業が全然進まず、大変困っております。
どうぞよろしくお願いいたします。

かるあ
ぬし
会議室デビュー日: 2003/11/16
投稿数: 1190
お住まい・勤務地: センガワ→ムサシノ
投稿日時: 2008-02-17 21:11
もうしばらく Oracle に触っていないので間違えているかも知れないけれど、
プロシージャだろうが、ファンクションだろうが同じ方法でできたと思いますよ。

今はどういった状況ですか?
エラーが出ている?出ているとしたらどんなエラー?

まずはサンプルと同じ構成で正常にストアドプロシージャを呼ぶことができるか試してください。(サンプルと全く同じテーブルを作って呼んでみる)
ストアドプロシージャとファンクションの違いって.NET側からは戻り値のパラメータを積むか積まないかの違いぐらいな気がする。


_________________
かるあ のメモスニペット
かるあ
ぬし
会議室デビュー日: 2003/11/16
投稿数: 1190
お住まい・勤務地: センガワ→ムサシノ
投稿日時: 2008-02-17 21:44
ありゃ、RSSを眺めてたらこっちにもあったのね。
とりあえずリンクしとくか
http://otn.oracle.co.jp/forum/thread.jspa?messageID=35022954&tstart=0#35022954
_________________
かるあ のメモスニペット
K-Kei
会議室デビュー日: 2004/09/01
投稿数: 7
投稿日時: 2008-02-18 19:38
かるあさん、レスポンスありがとうございます。
ストアドだけ載せたのでは判りにくいかなと思いましたので、C#側のコードも載せます。

--------------------------------- C#のコード
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Oracle.DataAccess.Client;

namespace SFTest
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private OracleConnection dbConnect;
private void Form1_Load(object sender, System.EventArgs e)
{
try {
String connString = "Data Source=XXXXX;User ID=XXXXX;password=XXXXX;";
dbConnect = new OracleConnection(connString);
if (dbConnect != null) {
lblConnStatus.Text = "connect success!!";
// lblConnInfo.Text = "Connected to Oracle" + dbConnect.ServerVersion;
}
dbConnect.Open();
}
catch (Exception econnect)
{
MessageBox.Show(econnect.Message);
}
}

private void button1_Click(object sender, System.EventArgs e)
{
try {
OracleCommand cmd = new OracleCommand(
"PKG_TEST.F1", dbConnect);

OracleParameter Param1 = cmd.Parameters.Add("1", OracleDbType.Int32);

Param1.Direction = ParameterDirection.Input;

Param1.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

Param1.Value = new int[3] {10, 20, 30};

Param1.Size = 3;

Param1.ArrayBindSize = new int[3] {2, 2, 2};

Param1.ArrayBindStatus = new OracleParameterStatus[3] {
OracleParameterStatus.Success,
OracleParameterStatus.Success,
OracleParameterStatus.Success};

cmd.ExecuteNonQuery();
}
catch (Exception ecmdbutton1click) {
MessageBox.Show(ecmdbutton1click.Message);
}
}
}
}

ちなみに出ているエラーは
ORA-00900:invalid SQL statement
です。
SQL文がおかしいということは理解できるのですが、どこがどうおかしいのか
見当がつきません。
かるあさんの仰るとおり、サンプルと同じ構成でプロシージャが呼べるかどうか
試してみることにします。
GENZO
大ベテラン
会議室デビュー日: 2003/11/26
投稿数: 111
お住まい・勤務地: 名古屋
投稿日時: 2008-02-18 23:36
環境がないので試していないですが、ストアドの場合
cmd.CommandType = CommandType.StoredProcedure
が必要だったような気が。。。
K-Kei
会議室デビュー日: 2004/09/01
投稿数: 7
投稿日時: 2008-03-25 11:49
レスが遅くなりましてすみません。自己解決しました。
以下のコードにて、動作を確認できました。
[pre]
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void btnExe_Click(object sender, System.EventArgs e)
{
// ORACLEコネクションの生成とコネクションのオープン
OracleConnection conn = new OracleConnection();
conn.ConnectionString = "User Id=" + tbxUserID.Text + ";Password=" + tbxPassword.Text + ";Data Source=" + tbxSID.Text;
conn.Open();

// ORACLEコマンドの生成
OracleCommand cmd = new OracleCommand(tbxFuncName.Text, conn);
cmd.CommandType = CommandType.StoredProcedure;

// パラメータのバインド
OracleParameter ret = cmd.Parameters.Add("ret", OracleDbType.Int32);
ret.Direction = ParameterDirection.ReturnValue;

OracleParameter param = new OracleParameter();
param.OracleDbType = OracleDbType.Int32;
OracleParameter param = new OracleParameter("vals", OracleDbType.Int32);
param.Direction = ParameterDirection.Input;
param.CollectionType = OracleCollectionType.PLSQLAssociativeArray;

string delimStr = ",";
char [] delimiter = delimStr.ToCharArray();
int [] num = null;
string [] values = null;
values = tbxParam1.Text.Split(delimiter,10);
num = new int[values.Length];
for (int i = 0 ; i < values.Length ; i++) {
num[i] = Int32.Parse(values[i]);
}
param.Size = values.Length;
param.Value = num;
cmd.Parameters.Add(param);

// コマンドの実行
cmd.ExecuteNonQuery();

// 戻り値の表示
tbxRetValue.Text = ret.Value.ToString();

// ORACLEコネクションのクローズとディスポーズ
conn.Close();
conn.Dispose();
}
[pre]

ご指摘いただいた皆様、どうもありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)