VB.NET2005+SQLserver2000です。
TableAdapterでの手動トランザクションについて
下記のようなコードで実現しようとしていますが、TableAdapter.Update時に
「ExecuteNonQuery は、コマンドに割り当てられた接続が保留状態であるローカルのトランザクションにあるとき、トランザクション オブジェクトを持つコマンドが必要です。コマンドの Transaction プロパティがまだ初期化されていません。」
というエラーになります。
--------------------------------------------------------------------
<クラスの定義>
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Reflection
Public Class MyTableAdapter
Public Shared Function BeginTransaction(ByVal tableAdapter As Object) As SqlTransaction
Return BeginTransaction(tableAdapter, IsolationLevel.ReadUncommitted)
End Function
Public Shared Function BeginTransaction(ByVal tableAdapter As Object, ByVal isolationLevel As IsolationLevel) As SqlTransaction
' get the table adapter's type
Dim type As Type = tableAdapter.GetType()
' get the connection on the adapter
Dim connection As SqlConnection = GetConnection(tableAdapter)
' make sure connection is open to start the transaction
If connection.State = ConnectionState.Closed Then
connection.Open()
End If
' start a transaction on the connection
Dim transaction As SqlTransaction = connection.BeginTransaction(isolationLevel)
' set the transaction on the table adapter
SetTransaction(tableAdapter, transaction)
Return transaction
End Function
''' <summary>
''' Gets the connection from the specified table adapter.
''' </summary>
Private Shared Function GetConnection(ByVal tableAdapter As Object) As SqlConnection
Dim type As Type = tableAdapter.GetType()
Dim connectionProperty As PropertyInfo = type.GetProperty("Connection", BindingFlags.NonPublic Or BindingFlags.Instance)
Dim connection As SqlConnection = CType(connectionProperty.GetValue(tableAdapter, Nothing), SqlConnection)
Return connection
End Function
''' <summary>
''' Sets the connection on the specified table adapter.
''' </summary>
Private Shared Sub SetConnection(ByVal tableAdapter As Object, ByVal connection As SqlConnection)
Dim type As Type = tableAdapter.GetType()
Dim connectionProperty As PropertyInfo = type.GetProperty("Connection", BindingFlags.NonPublic Or BindingFlags.Instance)
connectionProperty.SetValue(tableAdapter, connection, Nothing)
End Sub
''' <summary>
''' Enlists the table adapter in a transaction.
''' </summary>
Public Shared Sub SetTransaction(ByVal tableAdapter As Object, ByVal transaction As SqlTransaction)
' get the table adapter's type
Dim type As Type = tableAdapter.GetType()
' set the transaction on each command in the adapter
Dim commandsProperty As PropertyInfo = type.GetProperty("CommandCollection", BindingFlags.NonPublic Or BindingFlags.Instance)
Dim commands() As SqlCommand = CType(commandsProperty.GetValue(tableAdapter, Nothing), SqlCommand())
Dim command As SqlCommand
For Each command In commands
command.Transaction = transaction
Next
' set the connection on the table adapter
SetConnection(tableAdapter, transaction.Connection)
End Sub
End Class
--------------------------------------------------------------------
<使用時>
Using Cnn As New SqlClient.SqlConnection(My.Settings.Project1ConnectionString)
Dim Cmd As SqlClient.SqlCommand = Cnn.CreateCommand()
Cnn.Open()
Cmd.Transaction = Cnn.BeginTransaction
Call MyTableAdapter.SetTransaction(TableAdapter1, Cmd.Transaction)
Call MyTableAdapter.SetTransaction(TableAdapter2, Cmd.Transaction)
〜 データセット編集処理 省略 〜
TableAdapter1.Update(DataSet1.Table1) ← ここで上記エラー
〜 データセット編集処理 省略 〜
TableAdapter2.Update(DataSet1.Table2)
Cmd.Transaction.Commit()
End Using
--------------------------------------------------------------------
どこを改善すればよろしいでしょうか。
教えて下さい。
よろしくお願い致します。
とりあえずエラーメッセージでぐぐると幾つかの情報が得られました。
省略している部分も含めて、実行するコマンドを削って、どこまでは実行できて、
何を実行するとエラーになるか調べてください。
お返事ありがとうございました。
データセットの状態そのままではやはりうまく行きませんでした。
データセットを直接TableAdapter.UPDATEとするのではなく、
追加、変更、削除を行った結果のデータセットから
DataRow.RowStateの状態を見ながら、必要なSQL文(Addedなら
Insert文、DeletedならDelete文等)を生成し、
最終的に生成したSQL分をまとめてトランザクションとして
実行(command.ExecuteNonQueryを使用する通常の方法)するように
しました。
という訳で納得が行きませんが、解決とします。
お騒がせ致しました。
ツイート | ![]() |