Linq to SQL TransactionScope - PullRequest
       32

Linq to SQL TransactionScope

4 голосов
/ 10 февраля 2011

У меня есть следующий сценарий:

 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },EnterpriseServicesInteropOption.Automatic))
 {
  using (DataContext db = new DataContext())
  {
    db.Connection.Open();
    db.Transaction = db.Connection.BeginTransaction();
    try
    {
      bool outcome = InvokeInTransaction<string, object>(inputDict, out outputDict);
      db.Transaction.Commit();
    }
    catch (Exception ex)
    {
      response.Outcome = BusinessEntityResponse.SystemError;
      db.Transaction.Rollback();
    }
  }
}

Внутри вызова InvokeInTransaction есть ряд вызовов, сделанных в хранилище LTS для выполнения различных изменений данных.Проблема в том, что внутри хранилища есть еще один

using (var db = new DataContext())

, внутри которого находится постоянный код.Проверка контекста в репозитории показывает Transaction = null, и я подозреваю, что «внутренний» контекст не знает о транзакции Ambient.Можно ли это сделать?Я понимаю, что EF управляет этим под прикрытием, и ограничение заключается в том, что код хранилища не может быть изменен.Любая помощь?

1 Ответ

5 голосов
/ 12 февраля 2011

Мы используем LinqToSql и TransactionScope для нескольких транзакций базы данных.Вы действительно должны контролировать свои жизненные циклы соединения / контекста / транзакции, если вы собираетесь попробовать это.

  • Мы контролируем экземпляры DataContext по правилу: если вы создаете новый, вы делаете это с помощью оператора using.
  • Мы контролируем жизненные циклы соединения по правилу: если вы открываете его, вы должны закрыть его (но обычно это разрешают экземпляры DataContext).
  • Мы контролируем жизненные циклы транзакций по правилу: letDataContext управляет тем, что происходит в SubmitChanges, и позволяет TransactionScope управлять тем, что происходит внутри его блока использования.

Вот пример кода:

using (OuterDataContext outerDataContext = GetOuterDataContext())
{
  using (InnerDataContext innerDataContext = GetInnerDataContext())
  {
    try
    {
      OuterRepository outerRepository = new OuterRepository();
        // may read records into memory for updating/deleting.
      outerRepository.WorkWithOuterRecords(outerRecords, outerDataContext);

      InnerRepository innerRepository = new InnerRepository();
        // may read records into memory for updating/deleting.
      innerRepository.WorkWithInnerRecords(innerRecords, innerDataContext);

      using (TransactionScope scope = new TransactionScope())
      {
          //starts a local tranaction in outerDB, held open by scope
        outerDataContext.SubmitChanges();  
          //promotes the transaction to distributed, still held open by scope
        innerDataContext.SubmitChanges();
          // and done
        scope.Complete();
      }
    }
    catch (Exception ex)
    {
       LoggerClient.Log(ex);
       response.Message = "It didn't save anything.";
    }
  }
}
...