2010-01-04 2 views
1

У меня есть существующее приложение, которое использует много вызовов SqlTranaction. Путь строится приложение, которое мы получаем кучу кода, который выглядит немного как это (обработка ошибок и т.д. удалены для краткости):Как интегрировать унаследованный код SqlTransaction с TranactionScope?

Using transaction As SqlTransaction = Database.CreateSqlTransaction() 
    If Not Me.FitnessSession.FitnessTestSessionID.HasValue Then 
     Me.FitnessSession.Insert(transaction) 
    Else 
     Me.FitnessSession.Update(transaction) 
    End If 
    SaveTestScores(transaction) 

    Database.CommitTransaction(transaction) 'This essentially just calls transaction.Commit() 

End Using 

Мы находимся в процессе канав из стороны проката DAL и движется к Linq для SQL, но это будет постепенным, поскольку у нас нет бюджета, чтобы просто отбросить весь наш устаревший код. Таким образом, мы будем иметь области, где нам нужно использовать как наш старый код, так и код Linq to SQL, все в одной транзакции. Я считаю, что это можно сделать так:

Using scope As New TransactionScope() 
Using transaction As SqlTransaction = Database.CreateSqlTransaction() 
    If Not Me.FitnessSession.FitnessTestSessionID.HasValue Then 
     Me.FitnessSession.Insert(transaction) 
    Else 
     Me.FitnessSession.Update(transaction) 
    End If 
    SaveTestScores(transaction) 

    Database.CommitTransaction(transaction) 

End Using 
End Using 

Что я неясными на это который совершить вызов, я должен позвонить scope.Complete() или Database.CommitTransaction(transaction)? Или есть еще одна возможность связать два бита кода вместе?

Follow Up Вопрос
Спасибо @ программирования-героя, что действительно полезно, то, что я теперь не уверен в том, когда я должен закрыть SQL соединения? Код внутри методов DAL делает проверку, чтобы проверить, была ли она передана транзакция, если она есть, затем она использует соединение в этой транзакции и не закрывает соединение после его завершения, если транзакция не передается, а затем новый соединение открыто и закрыто для работы. Если я закрою SqlConnection внутри TransactionScope, это вызовет проблему для внешней транзакции? Я спрашиваю, потому что, если я закрываю SqlConnection, у которого есть объект SqlTransaction, транзакция откатывается.

ответ

2

Цель пространства имен System.Transactions - позволить вам управлять транзакциями из одной модели во всем приложении. При использовании модели транзакции, предоставленной System.Transactions, вам следует избегать использования каких-либо явных транзакций, таких как SqlTransaction; смешивание в явных транзакциях сделает вашу жизнь значительно сложнее, поскольку вам придется вручную управлять обеими моделями.

Отличная новость для вас: Когда вы используете компоненты ADO.NET, вы получаете поддержку встроенных внешних транзакций. Это означает, что вы можете удалить все ссылки на SqlTransaction и экземпляры объектов проходящих транзакций вокруг, так как модель System.Transactions будет заботиться обо всем для вас.

Модель внешней транзакции работает как обертка и координатор для различных других конкретных транзакций. Компоненты ADO.NET знают, как искать внешнюю транзакцию и самостоятельно настраивать свои собственные транзакции (например, SqlTransaction). Компоненты System.Transactions предупреждают все заверенные транзакции о состоянии «глобальной» транзакции, управляемой блоками TransactionScope.

При условии, что ваш код выполняется в блоке TransactionScope, для участия в транзакционных компонентах будет доступна внешняя транзакция. Для вашего кода доступа к данным все взаимодействия будут происходить в рамках одной и той же транзакции независимо от того, они являются частью ваших собственных компонентов DAL или Linq to SQL. Все, что вам нужно знать, это то, что они будут зачисляться во внешнюю транзакцию, если она присутствует.

Чтобы успешно завершить блок TransactionScope, просто позвоните TransactionScope.Complete() по местному экземпляру в конце работы. Сделайте это для каждого блока, в котором вы работаете, и когда заканчивается самый верхний блок, физические транзакции будут совершены.

Не нужно коллировать какой-либо другой код конкретной транзакции, так как все (за кадром) должны координироваться с вашим System.Transaction.

С учетом всего этого, ваш код может выглядеть следующим образом:

Using scope As New TransactionScope() 

    If Not Me.FitnessSession.FitnessTestSessionID.HasValue Then 
     Me.FitnessSession.Insert() 
    Else 
     Me.FitnessSession.Update() 
    End If 

    SaveTestScores() 

    scope.Complete() 

End Using 

Все ссылки на сделки с базами данных исчезли. Все операции будут выполняться в рамках внешней транзакции, предоставляемой TransactionScope. В этом блоке вы также можете сделать прямой вызов с помощью SqlCommand или использовать объект Linq-to-SQL без указания каких-либо явных транзакций, и они будут участвовать в внешней транзакции.

+2

Согласен. Одно из предостережений - «TransactionScope» будет эскалироваться в распределенную транзакцию (которая является PITA для развертывания), если весь код доступа к данным не имеет единого открытого объекта соединения. –

Смежные вопросы