- PR -

SqlDataSourceにトランザクションをかけて複数テーブルの更新

1
投稿者投稿内容
sakusaku
会議室デビュー日: 2005/11/16
投稿数: 15
投稿日時: 2007-03-15 19:48
こんばんは。

SqlDataSourceにトランザクションをかけて
複数テーブルのインサートや更新をかけたいと思っています。

以下を参考にして実現方法は確認できたのですが
ちょっと使い勝手が良くないので
他にも方法があれば、お聞かせ下さい。
(SqlDataSourceのこんな使い方自体、強引なんでしょうか?)

○参照サイト
http://kova.la.coocan.jp/blog/2006/03/sqldatasource.html


■環境
OS  :Windows Server 2003 R2 SP1
アプリ:Visual Studio 2005
SQL  :SQL Server 2005 SP1

=====================================================
■前提
・テーブルAとBの2つのテーブルがある。
・SqlDataSourceのIDは、「SqlDataSource1」
・テーブルAに対するインサートSQL文は、「sql」
・テーブルBに対するインサートSQL文は、「sql2」

=====================================================
■処理の流れ
(1)テーブルAをインサート時に発生するイベントで
  トランザクションをつける。

(2)テーブルAのインサートが終わった時に発生するイベントで
 テーブルBのインサート処理を行う。

(3)テーブルAとBのインサート結果件数(成功時は各々1になる)から
 ロールバックorコミットを行う。

=====================================================
■ソース
Dim sql As String = ""
Dim sql2 As String = ""

'インサート処理
Protected Sub DbInsert()
 sql = "INSERT INTO tableA …(省略)"
 sql2 = "INSERT INTO tableB …(省略)"


 Try
  SqlDataSource1.InsertCommand = sql
  SqlDataSource1.InsertCommandType = SqlDataSourceCommandType.Text
  intRetCnt = SqlDataSource1.Insert()
 Catch
 Finally
 End Try

End Sub


'(1)
Protected Sub SqlDataSource1_Inserting(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs) Handles SqlDataSource1.Inserting

 Dim command As DbCommand
 Dim connection As DbConnection
 Dim transaction As DbTransaction

 command = e.Command
 connection = command.Connection
 connection.Open()
 transaction = connection.BeginTransaction()
 command.Transaction = transaction
End Sub

'(2)
Protected Sub SqlDataSource1_Inserted(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs) Handles SqlDataSource1.Inserted

 Dim command As DbCommand
 Dim transaction As DbTransaction

 command = e.Command
 transaction = command.Transaction

 Dim intAffectA As Integer = 0
 Dim intAffectB As Integer = 0
 '-------------------------------
 'テーブルAの結果
 intAffectA = e.AffectedRows

 '-------------------------------
 'テーブルBの処理
 Try
  command.CommandText = sql2
  intAffectB = command.ExecuteNonQuery()
 Catch
 Finally
 End Try

 '-------------------------------
 '(3)
 '2つの更新結果による最終処理
 If intAffectA > 0 And intAffectB > 0 Then
  transaction.Commit()
 Else
  transaction.Rollback()
 End If

End Sub
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2007-03-16 12:54
何に関して"使い勝手が良くない"と思っていらっしゃるのかはわかりませんが、
例えばTransactionScopeによる暗黙的なトランザクションを利用すると、以下のように記述できます。(注:未検証)

コード:
Protected Sub DbInsert()
  Dim sql As String = "INSERT INTO tableA …(省略)"
  Dim sql2 As String = "INSERT INTO tableB …(省略)"


  Try
    SqlDataSource1.InsertCommand = sql
    SqlDataSource1.InsertCommandType = SqlDataSourceCommandType.Text
    Using scope1 As New System.Transactions.TransactionScope()
      Dim intAffectA As Integer = SqlDataSource1.Insert()
      Dim intAffectB As Integer

      Using connection1 As New SqlConnection(SqlDataSource1.ConnectionString);
        connection1.Open()
        Dim relationInsertCommand As New SqlCommand(sql2, connection1)
        intAffectB = relationInsertCommand.ExecuteNonQuery() 
        connection1.Close()
      End Using

      If ((1 = intAffectA) AndAlso (1 = intAffectB)) Then
        scope1.Complete()
      End If 
    End Using
  Catch
  Finally
  End Try

End Sub



まぁ、そもそもSqlDataSourceは単純な追加・更新・削除処理にしか向かないと思います。
(僕なら、SqlDataSourceに追加処理をやらせておきながらその後自分でデータアクセスしたりするのはNGです。)
sakusaku
会議室デビュー日: 2005/11/16
投稿数: 15
投稿日時: 2007-03-16 14:37
よこけん様 お返事ありがとうございます。

> 何に関して"使い勝手が良くない"と思っていらっしゃるのかはわかりません

言葉足らずで申し訳ありません。

私のテストプログラムでは、テーブルAのインサート実行時のイベントを拾って
トランザクションやテーブルBの処理を差し込む形になっています。
理想としては、SqlDataSourceを使わない手法と同じ流れで

Sub DbInsert()内だけで
(1)DB接続Open
(2)トランザクション開始
(3)テーブルAのインサート処理実行(ExecuteNonQuery)
  ※失敗したらDB接続Close
(4)テーブルBのインサート処理実行(ExecuteNonQuery)
  ※失敗したらロールバックして
   DB接続Close
(5)コミット
(6)DB接続Close

という処理の流れができれば、ソースが簡潔になるし
1つ目の処理(ここではテーブルAのインサート処理)が
インサート時は、Handles SqlDataSource1.Inserting
削除時は、Handles SqlDataSource1.Deleting …etc
といった1つ目の処理内容の事も考えなくても
同じロジックを使えるのに…と思ったんです。
(他ページで同じような処理があった時とか)

サンプルソースありがとうございます。
Sub DbInsert()内だけで処理が完結していて
スッキリしています!
参考にさせて頂きます。

> そもそもSqlDataSourceは単純な追加・更新・削除処理にしか向かないと思います。
やはり、そうですか。
アドバイスありがとうございます。

[ メッセージ編集済み 編集者: sakusaku 編集日時 2007-03-16 14:38 ]
1

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