Поддержка транзакций SqlConnection - PullRequest
0 голосов
/ 04 января 2012

Я пытаюсь добавить поддержку транзакций для нашего объекта базы данных. Этот объект является объектом удаленного взаимодействия. (это гарантирует, что на клиенте Windows не требуется подключение к базе данных.)

Теперь я хочу добавить поддержку транзакций; По сути, клиент должен будет использовать это так:

  1. BeginTransaction
  2. ExecuteNonQuery ( "вставить ...")
  3. ExecuteNonQuery ( "вставить ...")
  4. Фиксация / откат

<code>
Public Function ExecuteNonQuery(ByVal Query As String) As Integer
   Dim intResult As Integer = -1<br>
   Using conn As New SqlConnection(Me.strConnectionString)<br>
       Using cmd As New SqlCommand(Query, conn)<br>
          conn.Open()
          intResult = cmd.ExecuteNonQuery()<br>
       End Using 
   End Using 
   Return intResult 
End Function

Итак, проблема в том, что я не могу создать транзакцию, когда использую новое соединение (using conn...) в методе выше.

Так что я думаю, что мне нужно переместить экземпляр SqlConnection за пределы метода и изменить его на переменную уровня класса. Но это не лучшая практика, я думаю. (?) Кроме того: выполнение большого количества запросов в последовательности приводит к ошибке: «внутренняя фатальная ошибка».

Кто-нибудь может указать мне правильное направление? Все примеры, которые я нашел в Интернете, охватывают транзакции самым простым способом, выполняя сразу несколько запросов.

edit: это немного похоже на этот вопрос . (Как использовать одну SqlTransaction для нескольких SqlConnections в .NET?) . Так что, может быть, это просто невозможно, но есть ли обходной путь?

edit 2: Также кажется, что эта «внутренняя фатальная ошибка» возникает потому, что объект используется параллельно. Может быть, это просто невозможно?

Ответы [ 2 ]

1 голос
/ 04 января 2012

Я думаю, вам нужно будет сделать уровень подключения класса. Что я хотел бы сделать, это проверить, есть ли уже соединение, а затем, если нет, создать и транзакцию, если это необходимо. Отслеживание до тех пор, пока не будет вызван коммит или откат. Я не думаю, что есть что-то не так с использованием частного поля уровня класса в таком случае.

Примерно так:

Public Class SqlHandler
    Implements IDisposable

    Private mConnection As SqlConnection
    Private mTransaction As SqlTransaction
    Private strConnectionString As String

    Public Sub New()

    End Sub

    Public Sub New(UseTransaction As Boolean)
        mConnection = New SqlConnection
        If UseTransaction Then
            mTransaction = mConnection.BeginTransaction()
        End If
    End Sub

    Public Function ExecuteNonQuery(ByVal Query As String) As Integer
        Dim intResult As Integer = -1

        Using mConnection As SqlConnection
            Using cmd As New SqlCommand(Query, mConnection, mTransaction)
                cmd.Transaction = mTransaction
                mConnection.Open()
                intResult = cmd.ExecuteNonQuery()
            End Using
        End Using
        Return intResult
    End Function

    Public Sub Commit()
      If mTransaction IsNot Nothing Then
        mTransaction.Commit()
        mTransaction.Dispose()
      End If
          mConnection.Close()
          mConnection.Dispose()
    End Sub

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                If mTransaction IsNot Nothing Then
                    mTransaction.Rollback()
                    mTransaction.Dispose()
                End If
                If mConnection IsNot Nothing Then
                    mConnection.Close()
                    mConnection.Dispose()
                End If
            End If
        End If
        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

Я не проверял это, но это должно дать вам представление о том, что я имею в виду. Обязательно закройте и утилизируйте ваше соединение и транзакцию при каждом возможном стечении обстоятельств.

1 голос
/ 04 января 2012

Я думаю, вы можете поместить объект SqlConnection в качестве поля класса.

Class SQLHelp
    Implements IDisposable
    Private ReadOnly _conn As SqlConnection
    Private _trans As SqlTransaction

    Public ReadOnly Property Connection As SqlConnection
        Get
            Return _conn
        End Get
    End Property

    Sub New(strConnectionString)
        _conn = New SqlConnection(strConnectionString)
        _trans = Nothing
    End Sub

    Public Function ExecuteNonQuery(ByVal Query As String) As Integer
        Dim intResult As Integer = -1

        If _trans Is Nothing Then
            Using cmd As New SqlCommand(Query, _conn)

                If _conn.State <> ConnectionState.Open Then
                    _conn.Open()
                End If
                intResult = cmd.ExecuteNonQuery()

            End Using
        Else
            Using cmd As New SqlCommand(Query, _conn, _trans)

                If _conn.State <> ConnectionState.Open Then
                    _conn.Open()
                End If
                intResult = cmd.ExecuteNonQuery()

            End Using
        End If
        Return intResult
    End Function

    Public Function BeginTransaction() As SqlTransaction
        _trans = _conn.BeginTransaction()
        Return _trans
    End Function

    Public Sub SubmitTransaction()
        If Not (_trans Is Nothing) Then
            _trans.Commit()
        End If
        _trans = Nothing
    End Sub

    Public Sub RollbackTransaction()
        If Not (_trans Is Nothing) Then
            _trans.Rollback()
        End If
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose

        If Not (_trans Is Nothing) Then
            _trans.Dispose()
        End If

        _conn.Close()
        _conn.Dispose()

    End Sub
End Class

Когда вы используете этот класс, вы можете попробовать следующий код.Что вы думаете об этом?

...