2006年09月21日

Parameters の使用上の注意(ADO.NET)

SQLステートメントでパラメータを使用する場合にParametersプロパティに値をセットするが、連続してSQLを実行する場合、事前にパラメータの内容を消しておかないと同じ内容で処理されてしまうので注意する。
最初これに気が付かず、何故エラーするのか大いに迷ったことがある。

(Dim cmd As New OleDbCommand)
 
For i = 0 To 2
With Item(i)
cmd.CommandText = "insert into hoge_tb values(?,?,?)"
cmd.Parameters.Clear() 'これが無いとItem(0)の内容が3回登録されてしまう。
cmd.Parameters.Add("id", OleDbType.Integer).Value = .id
cmd.Parameters.Add("no", OleDbType.SmallInt).Value = i
cmd.Parameters.Add("namae", OleDbType.VarWChar).Value = .Name
cmd.ExecuteNonQuery()
End With
Next i

posted by なっちゃん at 14:44| 静岡 ☁| Comment(19) | TrackBack(0) | VB.NET Tips | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
今回のようなコードの場合、cmdをループの外で作成しているのならCommandTextとParametersの中身はループの外で作っておくべきでしょう。
ループの中では
cmd.Parameters(0).Value = .id
で値を設定します
それとAddした返り値オブジェクトに直接Valueを設定する書き方はどうかと思います。値を一緒に設定するなら別のAddを使うべきです。

文のパラメータより多い数のパラメータがあってもエラーが出なかったり同じパラメータ名を複数設定できてしまう仕様は微妙だと思いますが。
Posted by ほいほい at 2006年09月29日 15:39
仰る事の半分は判りますが、もう半分は理解できません。それと言うのもまだ使い方が判ってない部分があるからです。
Parameters.Add(xxx).value = yyyy はヘルプにもある使い方で、これが問題だという理由が判りません。
Posted by なっちゃん at 2006年09月29日 16:02
ほんとですか。そういうヘルプは私は見たことがないですね。

私がこれを問題だと思うのはコレクションへの
追加とその追加したアイテムへの操作を同時に
行っているからです。
2つのレベルの違うオブジェクトにつながり
のない別の操作をしているのが問題だと感じます。

Parameters.Add(xxx).value = yyyy
と書くなら
しかるべきアイテムを作成してから追加
Parameters.Add(New Parameter(xxx, yyyy
))
または
ただ追加した後、値を設定する
Parameters.Add(xxx, type)
Parameters(xxx).Value = yyyy
とでもすべきではということです。
Posted by ほいほい at 2006年09月29日 18:51
では、サンプルが掲載されているヘルプの場所を書いておきます。

ms-help://MS.VSCC.v80/MS.MSDN.v80/
MS.NETDEVFX.v20.ja/cpref4/html/
T_System_Data_OleDb_OleDbParameter.htm

ここに、

adapter.SelectCommand.Parameters.Add( _
"@CategoryName", OleDbType.VarChar, 80).Value = "toasters"

adapter.SelectCommand.Parameters.Add( _
"@SerialNum", OleDbType.Integer).Value = 239

という記述があります。
Posted by なっちゃん at 2006年09月29日 19:32
本当ですね。気づきませんでした。
でもたとえマイクロソフトのサンプルでも私はこのような書き方を薦めません。
前発言のような書き方を薦めます。
Posted by ほいほい at 2006年10月02日 18:23
古い記事へのコメントをご容赦ください。

こういう書き方は一般的に許されるべきだと思いますよ。
Addメソッドの戻り値がなぜこの型なのか?を考えると、まさにこういった使い方を想定しているからだと思いませんか?

VB系ではこういう書き方はあまりなじみが無いのかもしれませんが、他の言語では過去から良く使われる手法だと思います。
Posted by ざうたけ at 2008年02月13日 09:59
「よく使われる手法」というのは何かを混同されてると思います。

Addメソッドは文字通りパラメータを"追加"するわけですから、ループの中で使用するのはダメです。

例えば10万件のデータをInsertする用途で上記のコードを使用したらOut of Memoryになりますよ。
Posted by 通りすがり at 2008年07月11日 19:04
Out of Memory にはならないです。
Parameters.Clear() してますから。
Posted by なっちゃん at 2008年07月11日 19:33
cmd.Parameters.Clear()
ありがとうございました。
Posted by とがし at 2008年09月24日 11:26
確かに「Add」という名前なのに「追加したアイテムへ操作を同時にやっている」というのは変な感じもしますが、内容的には
//略したやり方
Parameters.Add(xxx).value = yyyy

//略さないやり方
ver
wAddItem: T?????????;
begin
wAddItem := Parameters.Add(xxx);
wAddItem.value = yyyy;
の略として考えられるので、この内容を「分かっていて」使っているのであれば、こう使っても問題ないと思います。

一長一短・好みがあるので、どちらが正解というのは難しいですが、今回の場合、私の好みは略さない方です。
Posted by hyahhooo at 2008年10月23日 10:01
↑思わずDelphiコード書いちゃった(汗)
まぁ、脳内でVBコードに変換して。
Posted by hyahhooo at 2008年10月23日 10:15
みなさん、この問題についていろいろご意見があるようですね。
でも、現場の人間としてはどうでもよいのです、動けば。(^o^;
Posted by なっちゃん at 2008年10月23日 10:48
>でも、現場の人間としてはどうでもよいのです、動けば。
確かに、動くのが最優先ですね(笑)

「良いコードが良いプログラムを生み出すわけではない」という格言をどっかのWebページで見た事があります。

コードの書き方のルールをあまり縛らずにコード書いた方が結局効率的だった、というのはよくある話です。

チーム内全員が同じルールで書ければいいでしょうけど、この手の話はたいてい喧嘩状態になります(笑)
Posted by hyahhooo at 2008年10月24日 13:25
あなたは自分の好きな書き方でいいかもしれませんが、
数年後にあなたがいない状況で他の誰かが修正を入れることになったとき、その書き方に悩まれる方が出てくるかもしれません。

可読性の観点から、将来の修正者のことを考えれば、分けて書くべきでしょう。
Posted by とーりすがり at 2009年03月04日 21:14
私には、何が問題なのか全然わかりません。
悩む人の気持ちがわからない。
もっとも、それ以外のことで人の書いたソースには大いに悩むものですが。
Posted by なっちゃん at 2009年03月04日 22:39
旧文にコメント失礼。

私も
Add(xxx).Value=??
という書き方でいいと思います。
# もちろんAddメソッドの戻りが何なのかが重要ですけど

Add(xxx).Value=??
という書き方がいやな方って、
プロパティやインデクサに対しても同様の意見をもってるんでしょうか?

BB.ToString(xxx).Trim()
とかもいやなんでしょうか?


# 規約のレベルでそういうのを禁止する現場があるのも
# 残念ながら事実です。

トリッキーすぎるのも困りものですが、
この程度のものに対して一々一時変数用意するというのは
(私にとっては)その方が可読性におとります。
Posted by DUNE at 2009年06月30日 13:23
旧文にコメント失礼します。

私的には書き方云々ではなく、無駄な動作が多いように思いますが。パラメータを追加して値をセットし、実行後、パラメータをクリアという複数の動きをループ内でさせるよりも、ループの外でパラメータを作成して、ループ内で値をセットし実行するだけの方がスマートなのではないでしょうか???
Posted by たまちゃん at 2009年11月09日 09:36
最初に書かれたコメントと同じですね。
ちょうど一巡しました。
Posted by なっちゃん at 2009年11月09日 13:05
CommandTextも変わらずパラメータ数も変わらないなら、
パラメータをAddして、
rs = cmd.executeして、
Value変えてからrequery使いなよ
どこにもループさせる意味はない
Posted by 奥隆博 at 2016年03月25日 17:19
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.seesaa.jp/tb/24141156
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。