- PR -

ODP.NETのFillメソッドでNull例外が発生する

1
投稿者投稿内容
GEMPMGR
会議室デビュー日: 2003/04/17
投稿数: 8
投稿日時: 2007-03-10 11:57
いつも参考にさせて頂いております。
現在、ASP.NET(VB)&ODP.NET+OracleでWebアプリケーションを構築しております。

【構成】Web+DBの1台構成です
OS             :Windows2000 Server
データベース         :Oracle 9.2.0.1.0
.NETフレームワーク      :1.1.4322
Oracle Data Provider for .NET:9.2.0.2102


【現象】
あるSQL(SELECT文)の実行時のみ、以下のエラーが発生する。

System.ArgumentNullException: キーを Null にすることはできません。
パラメータ名 : key
at System.Collections.Hashtable.get_Item(Object key)
at Oracle.DataAccess.Client.Pooler.Get(Object obj, Object key)
at Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior)
at Oracle.DataAccess.Client.OracleDataAdapter.Fill(DataTable dataTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
at xxxxxx.SelectExec(String sSql, OracleConnection& con, DataTable& dtTbl)


本システムの別機能においては、INSERT,SELECTに関わらず正常に動作しております。
また、問題のSQLをサーバ上のSQL*PLUSで実行した場合には、エラーが発生せず正しい結果を取得できます。
さらに、WindowsXP環境にWebサイトを構築して実行した場合も、エラーが発生せず正しい結果を取得できます。


【考察】
SQLに原因があると考え、問題のSQLと他処理で実行しているSQLを比較しました。違いは次の2点です。

1.他処理と比較してSQL文が長い(エラー:800行、他処理:100行未満) 行数ではあまり比較になりませんが…

2.内部処理にてStringBuilder型変数に対するSQL文の編集方法が異なる
 ○strSQL.Append("(SELECT …")ではなく
 ×strSQL.Append(" (SELECT …" & vbCrLf) と、数バイトの空白の後でSQLが始まる。また、行末に改行コードを埋め込んでいる。

しかし、SQL*PLUSでは正常に実行できることから、ODPや.NETフレームワークといった実行環境に問題がある気もしております。


【補足】
当サーバ上では、同様にODP.NETを用いた別システムが既に稼動しており、
必要なソフトウェアについては全て同じバージョンを使用し、プログラム開発を行いました。
そのため、アプリケーションの組み込み時にはインストールパッケージを用意せず、
新規Webサイト作成→開発機から実行フォルダをコピー→Web参照・IIS設定にて環境構築を行っております。


長くなり、読みにくくてすみません。
少しでも情報をお持ちの方がいらっしゃいましたら、アドバイスをお願い致します。
ぶさいくろう
ぬし
会議室デビュー日: 2005/11/22
投稿数: 1232
お住まい・勤務地: 川崎市(は俺も含めてロクな人間が住んでないよw)
投稿日時: 2007-03-10 12:27
引用:

GEMPMGRさんの書き込み (2007-03-10 11:57) より:
いつも参考にさせて頂いております。
現在、ASP.NET(VB)&ODP.NET+OracleでWebアプリケーションを構築しております。

【構成】Web+DBの1台構成です
OS             :Windows2000 Server
データベース         :Oracle 9.2.0.1.0
.NETフレームワーク      :1.1.4322
Oracle Data Provider for .NET:9.2.0.2102


【現象】
あるSQL(SELECT文)の実行時のみ、以下のエラーが発生する。

System.ArgumentNullException: キーを Null にすることはできません。
パラメータ名 : key
at System.Collections.Hashtable.get_Item(Object key)
at Oracle.DataAccess.Client.Pooler.Get(Object obj, Object key)
at Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior)
at Oracle.DataAccess.Client.OracleDataAdapter.Fill(DataTable dataTable, IDbCommand command, CommandBehavior behavior)
at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable)
at xxxxxx.SelectExec(String sSql, OracleConnection& con, DataTable& dtTbl)


本システムの別機能においては、INSERT,SELECTに関わらず正常に動作しております。
また、問題のSQLをサーバ上のSQL*PLUSで実行した場合には、エラーが発生せず正しい結果を取得できます。
さらに、WindowsXP環境にWebサイトを構築して実行した場合も、エラーが発生せず正しい結果を取得できます。


【考察】
SQLに原因があると考え、問題のSQLと他処理で実行しているSQLを比較しました。違いは次の2点です。

1.他処理と比較してSQL文が長い(エラー:800行、他処理:100行未満) 行数ではあまり比較になりませんが…

2.内部処理にてStringBuilder型変数に対するSQL文の編集方法が異なる
 ○strSQL.Append("(SELECT …")ではなく
 ×strSQL.Append(" (SELECT …" & vbCrLf) と、数バイトの空白の後でSQLが始まる。また、行末に改行コードを埋め込んでいる。

しかし、SQL*PLUSでは正常に実行できることから、ODPや.NETフレームワークといった実行環境に問題がある気もしております。


【補足】
当サーバ上では、同様にODP.NETを用いた別システムが既に稼動しており、
必要なソフトウェアについては全て同じバージョンを使用し、プログラム開発を行いました。
そのため、アプリケーションの組み込み時にはインストールパッケージを用意せず、
新規Webサイト作成→開発機から実行フォルダをコピー→Web参照・IIS設定にて環境構築を行っております。


長くなり、読みにくくてすみません。
少しでも情報をお持ちの方がいらっしゃいましたら、アドバイスをお願い致します。


違いであげたものは正直かんけーないと思う。
てきとうによみかえたSQLをここに書いてくれねーかな?

つか。例外どおりでキーをNullにしてるだけなんじゃねーの。ダメだよ。
ほかのところではうまくいくってホンマかいな?
GEMPMGR
会議室デビュー日: 2003/04/17
投稿数: 8
投稿日時: 2007-03-10 21:56
ぶさいくろう様
返信ありがとうございます。

肝心の顧客環境でだけエラーになるので、困っている次第です。
実際、ハッシュテーブルを参照する際のキーがNullというのは、どういう状態なのでしょうか?
てっきりODPの内部処理でエラーが発生しているものと思っていたのですが…


仕様概略
1.キー項目a1件に対して、常に4行を画面に表示(aはテーブルAというマスタで管理)
2.1〜3行目はテーブルBから値を取得(どの行の値となるかは、テーブルB中に区分で保持)
3.4行目はテーブルCから値を取得
4.テーブルAのレコードは削除される可能性があり、その場合も常に4行必要(Aが存在する場合はAの情報が優先)

[画面]4行で1かたまりのイメージ
行 キー 値(Q04) 区分
1 a 100 0 ←テーブルBから
2 a 0 1 ←テーブルBから
3 a 1,000 2 ←テーブルBから
4 a 500 9 ←テーブルCから
↑テーブルAから

そのため、


1−1.
[テーブルAから]キー:aを抽出し、値0で3レコード作成
 キー 値(Q04) 区分
 a 0 0
 a 0 1
 a 0 2

UNION ALL
1−2.
[テーブルA&Bから]
 キー 値(Q04) 区分
 a 100 0
 a 1,000 2

UNION

1−3.
 [テーブルBから]キー:aを抽出し、値0で3レコード作成
 キー 値(Q04) 区分
 a    0  0
 a    0  1
 a   0  2

UNION ALL
1−4.
 [テーブルBから]
 キー 値(Q04) 区分
 a   100  0
 a  1,000  2


UNION ALL

 (省略)同様に、テーブルA:テーブルCについても取得しています


としています。SQLは、下記のようなカンジです。
GEMPMGR
会議室デビュー日: 2003/04/17
投稿数: 8
投稿日時: 2007-03-10 21:59
SQLです。
実際はCASEやCOALESCEを使用しており、更に見にくくなっています。

/*UNION1 ↓*/
(
SELECT
キー,
区分,
TOTAL.更新日付,
DECODE(INSTR(Q04,'.'),0,TO_CHAR(Q04,'FM9,990'),TO_CHAR(Q04,'FM9,990.999999')) Q04
FROM
/*テーブルA、テーブルBのUNIONテーブルを集計 ↓*/
(
SELECT
キー,
区分,
MAX(更新日付) 更新日付,
SUM(Q04) Q04
FROM
/*テーブルA、テーブルBのUNIONテーブル ↓*/
(
(
/*UNION1−1:テーブルAを検索し、ALL0値の行を3件作成する ↓*/
(
SELECT
テーブルA.キー,
区分マスタ.区分,
NULL 更新日付,
0 AS Q04
FROM
テーブルA,
区分マスタ
WHERE
区分マスタ.区分 IN ('0','1','2')
)
/*UNION1−1:テーブルAを検索し、ALL0値の行を3件作成する ↑*/
UNION ALL
/*UNION1−2:テーブルA、テーブルBを検索し、値が存在するものを抽出する ↓*/
(
SELECT
テーブルB.キー,
テーブルB.区分,
テーブルB.更新日付,
CASE テーブルB.MONTH WHEN '04' THEN テーブルB.QUANTITY ELSE 0 END Q04
FROM
テーブルA,
テーブルB
WHERE
(テーブルB.区分 = '0' OR
テーブルB.区分 = '1' OR
テーブルB.区分 = '2' ) AND
テーブルB.キー = テーブルA.キー
)
/*UNION1−2:テーブルA、テーブルBを検索し、値が存在するものを抽出する ↑*/
)
UNION
(
/*UNION1−3:テーブルBを検索し、ALL0値の行を3件作成する ↓*/
(
SELECT DISTINCT
テーブルB.キー,
区分マスタ.区分,
NULL AS 更新日付,
0 AS Q04
FROM
テーブルB,
区分マスタ
WHERE
区分マスタ.区分 IN ('0','1','2')
)
/*UNION1−3:テーブルBを検索し、ALL0値の行を3件作成する ↑*/
UNION ALL
/*UNION1−4:テーブルBを検索し、値が存在するものを抽出する ↓*/
(
SELECT
テーブルB.キー,
テーブルB.区分,
テーブルB.更新日付,
CASE テーブルB.MONTH WHEN '04' THEN テーブルB.QUANTITY ELSE 0 END Q04
FROM
テーブルB
WHERE
(テーブルB.区分 = '0' OR
テーブルB.区分 = '1' OR
テーブルB.区分 = '2' )
)
/*UNION1−4:テーブルBを検索し、値が存在するものを抽出する ↑*/
)
)
/*テーブルA、テーブルBのUNIONテーブル ↑*/
GROUP BY
キー,
区分
) TOTAL
/*テーブルA、テーブルBのUNIONテーブルを集計 ↑*/
)
/*UNION1 ↑*/

UNION ALL
/*UNION2 ↓*/

-- (省略)同様に、テーブルA:テーブルCについても取得しています

/*UNION2 ↑*/

ORDER BY
キー
区分


何卒、宜しくお願い致します。
NAL-6295
ぬし
会議室デビュー日: 2003/01/26
投稿数: 966
お住まい・勤務地: 東京
投稿日時: 2007-03-11 14:18
NAL-6295です。

日本語ではありませんが、

Key cannot be null. Parameter name: key
http://forums.oracle.com/forums/thread.jspa?threadID=220724

という同じ問題についてのスレッドがありました。

また、ODP.NETのバージョンが最新では無いようですね。
GEMPMGR
会議室デビュー日: 2003/04/17
投稿数: 8
投稿日時: 2007-03-11 21:58
NAL-6295様

返信ありがとうございます。
ご教示頂いたサイトを参照しましたが、UNIONの使用や、"("で始まるSQL…思い当たる節があります。

問題の環境への組み込み時にはインストールパッケージを使用していないため、
実はバージョンの異なるODP.NETが別のフォルダにもあり、そちらを参照しているのではないか…などと考えております。

一度、動作環境の確認をしてみることにします。
GEMPMGR
会議室デビュー日: 2003/04/17
投稿数: 8
投稿日時: 2007-03-13 02:59
動作環境確認の結果、ODP9.2.0.4がインストールされた環境で実行すると上記現象が発生することが判りました。
NAL-6295様から教えて頂いたサイトにもあるように、バージョン9.2.0.4にはどうも問題があるようです。

そこでインストールパッケージを作成し、正常に動作するODP9.2.0.2を仮想ディレクトリのbinフォルダ下に配置したのですが、回避できませんでした。
未だ9.2.0.4の方を参照しているようです。
試しに、GACに両バージョンを共存させてもダメでした。。

ODP.NETとは「OracleDataAccell.dll」だけではないのでしょうか?
既に顧客環境に存在するODP9.2.0.4を削除するわけにはいかないので、今回のシステムのみ9.2.0.2を参照させたいのですが…
GEMPMGR
会議室デビュー日: 2003/04/17
投稿数: 8
投稿日時: 2007-03-24 17:50
遅くなりましたが、解決しましたのでご連絡致します。
結局、ODP9.2.0.4で動作させることとしました。

他の箇所でも試してみましたが、9.2.0.4で"("から始まるSQLを実行する際は、
必ず「キーを Null にすることはできません。」エラーが発生することが判りました。

そこで、SELECT文括っていたカッコを取り除いたところ9.2.0.4でもエラーが発生しなくなったため、同件全てを対策して動作確認を実施しました。
リリース後、現在は問題なく稼動しております。

アドバイス頂いた方々、ありがとうございました。
1

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