Рефакторинг ADO.NET - SqlTransaction против TransactionScope

Я "унаследовал" небольшой метод С#, который создает объект ADO.NET SqlCommand и перебирает список элементов, которые будут сохранены в базе данных (SQL Server 2005).

В настоящий момент используется традиционный подход SqlConnection/SqlCommand, и чтобы убедиться, что все работает, два этапа (удаление старых записей, а затем вставка новых) завернуты в ADO.NET SqlTransaction.

using (SqlConnection _con = new SqlConnection(_connectionString))
{
   using (SqlTransaction _tran = _con.BeginTransaction())
   {
      try
      {
         SqlCommand _deleteOld = new SqlCommand(......., _con);
         _deleteOld.Transaction = _tran;
         _deleteOld.Parameters.AddWithValue("@ID", 5);

         _con.Open();

         _deleteOld.ExecuteNonQuery();

         SqlCommand _insertCmd = new SqlCommand(......, _con);
         _insertCmd.Transaction = _tran;

         // add parameters to _insertCmd

         foreach (Item item in listOfItem)
         {
            _insertCmd.ExecuteNonQuery();
         }

         _tran.Commit();
         _con.Close();
       }
       catch (Exception ex)
       {
          // log exception
          _tran.Rollback();
          throw;
       }
    }
}

Теперь я много читал о классе .NET TransactionScope, и мне было интересно, какой предпочтительный подход здесь? Получил бы я что-нибудь (читаемость, скорость, надежность), переключившись на использование

using (TransactionScope _scope = new TransactionScope())
{
  using (SqlConnection _con = new SqlConnection(_connectionString))
  {
    ....
  }

  _scope.Complete();
}

Что бы вы предпочли и почему?

Марк

Ответ 1

Вы ничего не получите сразу, переключив свой существующий код на TransactionScope. Вы должны использовать его для будущего развития из-за гибкости, которую он предоставляет. Это облегчит в будущем включение в транзакцию других событий, кроме вызовов ADO.NET.

Кстати, в вашем опубликованном примере экземпляры SqlCommand должны быть в блоках using.

Ответ 2

Корпорация Майкрософт рекомендует использовать область транзакций:

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

Основная идея заключается в том, что область транзакций будет управлять контекстом внешней транзакции для вас. Вы начинаете с разговора с одной базой данных, у вас есть транзакция sql, затем вы разговариваете с номером базы данных 2, а транзакция добавляется к распределенной транзакции.

Область транзакций работает для вас, так что вы можете сосредоточиться на функциональности системы, а не на сантехнике.

ИЗМЕНИТЬ

При использовании области транзакции все в пределах этой области охвачено транзакцией. Поэтому вы сохраняете строку кода, в которой вы связываете команду с транзакцией. Это возможный источник ошибок, например, если в 1000 был один шанс, что эта линия была забыта, сколько бы вы не пропали без вести.

РЕДАКТИРОВАТЬ 2

Согласен с комментарием Триинко ниже. Однако мы используем Entity Framework, EF автоматически закрывает и снова открывает соединение, чтобы заручиться его в транзакции. Он физически не закрывает соединение больше, он выпускает его в пул соединений и получает новый, который может быть одним и тем же или может быть другим.

Ответ 3

Я предпочитаю TransactionScope. Это не работает отлично в каждом сценарии, но в том, что вы описываете, это лучшее решение.

Мое рассуждение:

  • Зачисление в транзакцию выполняется автоматически
  • Откат транзакции в случае исключения является автоматическим

Вместе результат - это немного меньше кода и, как правило, более надежный дизайн, поскольку система обрабатывает некоторые детали для меня; это еще одна вещь, которую я должен помнить.

Кроме того, прозрачная регистрация транзакций может быть особенно полезна, когда у вас есть несколько вложенных методов в вашем DAL - хотя вам нужно позаботиться о том, чтобы ваша транзакция случайно не превратилась в распределенную, которая требует кода DTC, который может случиться, если вы используете несколько SqlConnections, даже если они указывают на один и тот же БД.

Ответ 4

Просто обратите внимание, что с помощью области транзакций иногда возникает большая проблема, потому что многие настройки, которые мы должны делать на сервере, такие как установка DTC, брандмауэра и т.д. Поэтому я рекомендовал использовать SqlTransaction, более сэкономить на реализации.

Ответ 5

Хорошо, может быть, слишком поздно для этого... но, во всяком случае, я запишу это для тех, кого это интересует...

Так как у меня есть лучшая картина сейчас, после большого количества трудностей с моим текущим подходом SqlTransaction, который я мог бы изменить в пользу TransactionScope, как я вижу... главное преимущество TransactionScope что можно легко использовать в бизнес-слое.

Ответ 6

Также поздно... Вы можете легко иметь "вложенные" транзакции на бизнес-уровне, даже если база данных не поддерживает вложенные транзакции..NET управляет вложением и заканчивается использованием одной транзакции базы данных (по крайней мере, в случае SQL Server 2008+). Это значительно упрощает повторное использование кода доступа к данным за пределами его первоначального намерения как части более крупной транзакции.