- PR -

見たことありますか?OracleDataAdapter で、No size set for variable length data type: String

1
投稿者投稿内容
naomix
ベテラン
会議室デビュー日: 2003/02/01
投稿数: 56
投稿日時: 2004-05-21 23:39
非常に悩んでいます。ピンチです。
OracleDataAdapter で取得したデータに、長さ0の文字列 "" を設定して、
Updateすると以下の例外が発生します。

System.Exception: Parameter 'p2': No size set for variable length data type: String.

これ何ですか?
しかも、""を代入したのは p2 の位置ではないはずなのです。
その他の値なら問題ありません。
腑に落ちない。

誰か教えてください。お願いします。

コードはざっとこんな感じです。

コード:
OracleConnection conn = new OracleConnection(<接続文字列>);
OracleCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * "
	+      "  from  table1"
	+      "  where data1 = :data1"
	+      "  and   data2 = :data2";

cmd.Parameters.Add("data1", OracleType.Char, 7).Value = "1234567";
cmd.Parameters.Add("data2", OracleType.Char, 6).Value = "123456";

OracleDataAdapter adapter = new OracleDataAdapter(cmd);
DataSet ds = new DataSet();
adapter.Fill(ds);

OracleCommandBuilder builder = new OracleCommandBuilder (adapter);
adapter.InsertCommand = builder.GetInsertCommand();
adapter.UpdateCommand = builder.GetUpdateCommand();

DataTable dt = ds.Tables[0];
DataRow row = dt.Rows[0];
row["data3"] = "";
adapter.Update (ds);


Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-05-22 00:29
 Oracleのマニュアルを、よく見ましょう。

 Oracleでは、長さ0の文字列はNULLとして扱われます。UPDATE文が転記されていないので詳しいところはわかりませんが、その辺の演算子の指定を間違っていると思います。

 特に、CommandBuilderを使われていますが、これはオプティミスティック同時実行制御をするのではなかったでしょうか。そうすると、全データのオリジナル値とデータベース上の値を比較するUPDATE文を作ります。元のデータにNULL可能な列があると、支障が出ることが予想されます。
naomix
ベテラン
会議室デビュー日: 2003/02/01
投稿数: 56
投稿日時: 2004-05-22 01:17
Jittaさん、ありがとうございます。

引用:

Jittaさんの書き込み (2004-05-22 00:29) より:
 Oracleのマニュアルを、よく見ましょう。
 Oracleでは、長さ0の文字列はNULLとして扱われます。


そうなんですか?それは知りませんでした。
しかし、
row["data3"] = "";
を、
row["data3"] = System.DBNull.Value;
にしてみると、大丈夫なんですが。
これは、NULL入れても大丈夫ってことですよね。

引用:

 特に、CommandBuilderを使われていますが、これはオプティミスティック同時実行制御をするのではなかったでしょうか。そうすると、全データのオリジナル値とデータベース上の値を比較するUPDATE文を作ります。
元のデータにNULL可能な列があると、支障が出ることが予想されます。


オプティミスティック同時実行制御のことも念頭にあって、
UpdateCommand を自動生成させたんですが、
元のデータにNULLがあっても大丈夫なようにSQLが作られんじゃなかったでしたっけ?
実際作られたSQLを見てみると、
@ITの記事
http://www.atmarkit.co.jp/fdotnet/basics/adonet06/adonet06_03.html
のようなSQLが作られているので、
大丈夫そうな気がするのですが。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-05-24 09:59
 む〜?NULL処理の為に、トリッキーなことをしますねぇ...

 ところで、Oracle側の型はCHARですか?VARCHAR2ではなく?そうすると、「固定幅」ですよね。DbNullであれば、NULLであることが明白ですが、長さ0の文字列は、.NET Frameworkの中では「長さ0の文字列」、Oracle側では「ヌル」として扱うのではないでしょうか。すると、.NET Frameworkが「サイズ0の文字列」を、「サイズ固定の列」に対して設定しようとしていることになります。このため、「No size set for variable length」、「変数の長さを設定することはできない」となるのではないでしょうか。

 とにかく、Oracleの「長さ0の文字列=NULL」というのは、色々とバグや勘違いの温床なので(例えば、検索条件として未入力の項目をそのまま渡すと検索できなくなる、など)、可能ならばNOT NULLにするか、事前に定義した長さ分の「空白文字列」に置き換えるなどの手間が必要です。
naomix
ベテラン
会議室デビュー日: 2003/02/01
投稿数: 56
投稿日時: 2004-05-24 21:12
またまた、ありがとうございます。
Jittaさんの有意義な示唆により、無益な時間を費やさずに済みそうです。

UpdateCommand を、自動生成はやめて、SQLをよく考えて、自前で作ったら、
row["data3"] = "";
が、問題なく更新できるようになりました。

Oracle側の型はCHARです。

引用:

.NET Frameworkが「サイズ0の文字列」を、「サイズ固定の列」に対して設定しようとしていることになります。このため、「No size set for variable length」、「変数の長さを設定することはできない」となるのではないでしょうか。


そうなんでしょうか。よくわかりません。
更なる研究がいりそうです。

引用:

 とにかく、Oracleの「長さ0の文字列=NULL」というのは、色々とバグや勘違いの温床なので(例えば、検索条件として未入力の項目をそのまま渡すと検索できなくなる、など)、可能ならばNOT NULLにするか、事前に定義した長さ分の「空白文字列」に置き換えるなどの手間が必要です。


確かに厄介ですね。
1

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