2011-02-10 2 views
4

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

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 управляет этим под обложками, а ограничение заключается в том, что код репозитория не может быть изменен. Любая помощь?

ответ

5

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

  • Мы управляем экземплярами DataContext по правилу: если вы новый, вы делаете это с помощью оператора using.
  • Мы управляем жизненными циклами соединения по правилу: если вы его открываете, вы должны закрыть его (но, как правило, это позволяет экземплярам DataContext).
  • Мы управляем жизненными циклами транзакций по правилу: пусть DataContext управляет тем, что происходит в 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."; 
    } 
    } 
} 
+0

Спасибо Дэвид, эта модель, безусловно, выглядит хорошую реализацию, мне нравится WorkWith * отчеты как средство поддержания контекстных сфер, я просто не в состоянии получить вокруг моей коричневой области реализации классов репозитория (слишком много рефакторинга, чтобы делать на звонящих в эти классы). Отсюда исходный вопрос. Хороший узор, хотя .. – OldBoy

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