- - PR -
ODP.NETのFillメソッドでNull例外が発生する
1
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 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設定にて環境構築を行っております。 長くなり、読みにくくてすみません。 少しでも情報をお持ちの方がいらっしゃいましたら、アドバイスをお願い致します。 | ||||
|
投稿日時: 2007-03-10 12:27
違いであげたものは正直かんけーないと思う。 てきとうによみかえたSQLをここに書いてくれねーかな? つか。例外どおりでキーをNullにしてるだけなんじゃねーの。ダメだよ。 ほかのところではうまくいくってホンマかいな? | ||||
|
投稿日時: 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は、下記のようなカンジです。 | ||||
|
投稿日時: 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 キー 区分 何卒、宜しくお願い致します。 | ||||
|
投稿日時: 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のバージョンが最新では無いようですね。 | ||||
|
投稿日時: 2007-03-11 21:58
NAL-6295様
返信ありがとうございます。 ご教示頂いたサイトを参照しましたが、UNIONの使用や、"("で始まるSQL…思い当たる節があります。 問題の環境への組み込み時にはインストールパッケージを使用していないため、 実はバージョンの異なるODP.NETが別のフォルダにもあり、そちらを参照しているのではないか…などと考えております。 一度、動作環境の確認をしてみることにします。 | ||||
|
投稿日時: 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を参照させたいのですが… | ||||
|
投稿日時: 2007-03-24 17:50
遅くなりましたが、解決しましたのでご連絡致します。
結局、ODP9.2.0.4で動作させることとしました。 他の箇所でも試してみましたが、9.2.0.4で"("から始まるSQLを実行する際は、 必ず「キーを Null にすることはできません。」エラーが発生することが判りました。 そこで、SELECT文括っていたカッコを取り除いたところ9.2.0.4でもエラーが発生しなくなったため、同件全てを対策して動作確認を実施しました。 リリース後、現在は問題なく稼動しております。 アドバイス頂いた方々、ありがとうございました。 |
1