- ベストアンサー
一つのトランザクションでSELECTとUPDATEできますか? (ADO.NET)
いつもお世話になっております。 ADO.NETの話なのですが、トランザクションを開始したコネクションオブジェクトで DataAdapterを使ったSELECTと、ExecuteNonQueryを使ったUPDATEを交互に繰り返し 行うことはできるでしょうか? 現状できていないので可能なのであれば共通関数の見直しが必要かと思っています。 いまはSELECTとUPDATEを別のコネクションで行っているのですが、UPDATE後に 同じテーブルの該当レコードをSELECTにいくため、デッドロックが発生しています。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>それにしてもコネクションとトランザクションオブジェクトを別々に >渡してやる必要性がよく理解できません。コネクションオブジェクトから >トランザクションオブジェクトも参照できるのでは?と思うのですが・・・。 たしかに私も腑に落ちない・・・気がします なにか別に設定が必要な理由があるのかも知れませんね 複数のトランザクションが存在する場合に指定が必要になるのかも! 私の過去のコードにはしっかり sqlCommand.Transaction = tran がありました(いつの間にか記述してたみたい) すいません。#2ではまったくその事に触れていませんでした 憶測での回答になってしまいますが トランザクションが割り当てられたコマンドが実行されたときに 自動的にBegin Tranされ トランザクションが割り当てられていないコマンドが実行されたときに 自動的にCommit Tranが実行されてしまうのかも知れません 時間があったら実証して見たいと思います
その他の回答 (2)
- 7marine
- ベストアンサー率36% (59/160)
実はあまり知られていないことなのですが DataAdapterは複数のテーブルまたは全く関連のないテーブル、さらに同時に複数のテーブル、さらにさらにストアドプロシージャを指定してselect,update,insert,deleteを行うことが可能です その方法は割愛しますが、ウィザードだけを使用していると見落としがちですね(笑 ただコーディング実装が難しい部類になるので上級者むけですが 1~4を全てDataAdapterだけで実現することも可能です。 更新の反映はDataAdapter.Update()だけで済むのですが CommandオブジェクトとTableMappingの関連付けがやや難しいです 自信が無ければ上記は一度忘れて構いません 別の解決方法 1、DataAdapterのSelectCommandのConnectionをUpdateコマンドのConnectionに割り当てること 2、FillやUpdateを行う前にConnectionをOpenし全ての処理が終わってからCloseすること 何故そうするか? DataAdapterのFillコマンドはSelectCommandのConnectionの状態をFill前と後で維持します。 冗長して説明するとFillする前にCloseである場合は自動的にOpenしてからFillの後に自動的にCloseします。逆にOpenである場合はFillのみ処理を行います。 ですのでFillを行う前にConnectionをOpenする処理が無ければFill後に一度Closeしようとするのでトランザクションがぶつ切りになる可能性があります。updateまで含めて一連のトランザクションしたいのであれば、わざわざ手動でConnectionをOpen・Closeする必要があります。 >DataAdapterをCloseしたら、ExecuteNonQueryも >使えるようになるんですかね? 先の質問の答えはYesですが、一度CloseしてCommandオブジェクトのExecuteNonQueryを実行した場合はトランザクションの意味がなくなる可能性があります
- 7marine
- ベストアンサー率36% (59/160)
可能です。ただ疑問があります。 なぜDataAdapterでUpdateの処理まで行わないのでしょう。 推測ですが。。。 DataTableに結合クエリでfillしているのであれば UpdateCommand,InsertCommand,DeleteCommandを 自作する必要がありますが、同じようなことはできるかもしれません
補足
結合クエリというのはちょっと分からないのですが、 DataAdapterでUPDATEしない理由は、単純に1つの テーブルをSELECTしてUPDATEするわけ ではないことと、もう一つはSELECTしてくる共通関数 がUPDATEを考慮していないことが原因です。 (1)テーブルA から SELECT (2)(1)のデータでテーブルB から SELECT (3)(2)のデータでテーブルC に INSERT (4)テーブルA をUPDATE 上記の処理を繰り返し行うようなロジックになっています。 DataAdapterをCloseしたら、ExecuteNonQueryも 使えるようになるんですかね?
お礼
アドバイスありがとうございます。 共通関数を使わずにDataAdapterとExecuteNonQueryを使ってみたところ、 トランザクションを開始した接続オブジェクトで問題なく動作しました。 共通関数の中身を確認したところ、データアダプター使用時に Da = New SqlDataAdapter(strSQL, SqlCn) と宣言していたのが問題だったようです。 トランザクションを開始した接続オブジェクトでデータアダプターを 使うには、下記のような形でトランザクションオブジェクトも指定して やることが必要でした。 Da = New SqlDataAdapter Da.SelectCommand = New SqlCommand(strSQL, SqlCn, Trans) それにしてもコネクションとトランザクションオブジェクトを別々に 渡してやる必要性がよく理解できません。コネクションオブジェクトから トランザクションオブジェクトも参照できるのでは?と思うのですが・・・。