Linq to 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 управляет этим под прикрытием, и ограничение заключается в том, что код хранилища не может быть изменен. Любая помощь?
1 ответ
Мы используем LinqToSql и TransactionScope для нескольких транзакций базы данных. Вы должны действительно контролировать свои жизненные циклы соединения / контекста / транзакции, если вы собираетесь попробовать это.
- Мы контролируем экземпляры DataContext по правилу: если вы создаете новый, вы делаете это с помощью оператора using.
- Мы контролируем жизненные циклы соединения по правилу: если вы открываете его, вы должны закрыть его (но обычно это разрешают экземпляры DataContext).
- Мы контролируем жизненные циклы транзакций по правилу: пусть DataContext управляет тем, что происходит в SubmitChanges, и позволяет TransactionScope управлять тем, что происходит в его блоке using.
Вот пример кода:
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.";
}
}
}