В настоящее время я использую TransactionScope для управления транзакциями на моем уровне данных, но у меня возникли проблемы с вложенными транзакциями и асинхронным способом, при которых соединение, кажется, закрывается во время вложенной транзакции или транзакция продвигается в MSDTC. Я не нашел точной проблемы, но после прочтения это выглядит так, что этот сценарий не поддерживается particuarly well и вместо этого я должен использовать Database.BeginTransaction().Взаимодействие с вложенными транзакциями в EF6
Моя проблема заключается в том, что я не могу найти информацию о том, как Database.BeginTransaction() работает с вложенными транзакциями, особенно в моем сценарии, когда я хочу использовать внешнюю транзакцию, а не создавать новую. Мое подозрение в том, что он не предназначен для работы таким образом, и если я хочу управлять вложенными транзакциями, я должен абстрагироваться от управления транзакциями, чтобы дать мне больше контроля.
Не желая добавлять лишние слои абстракций Я хотел знать, есть ли у кого-либо опыт в этой области и может подтвердить поведение Database.BeginTransaction(), когда он вложен в другую транзакцию?
Дополнительная информация о моей DAL: на основе CQS рисунка, я, как правило, чтобы инкапсулировать Db код, связанный в командных или запроса обработчиков, поэтому упрощенный/надуманный пример того, как происходит это вложенности будет:
public class AddBlogPostHandler
{
private readonly MyDbContext _myDbContext;
public AddBlogPostHandler(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task ExecuteAsync(AddBlogPostCommand command)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// .. code to create and add a draft blog post to the context
await _myDbContext.SaveChangesAsync();
var publishBlogPostCommand = new PublishBlogPostCommand();
// ..set some variables on the PublishBlogPostCommand
await PublishBlogPostAsync(command);
scope.Complete();
}
}
}
public class PublishBlogPostHandler
{
private readonly MyDbContext _myDbContext;
public PublishBlogPostHandler(MyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
public async Task ExecuteAsync(PublishBlogPostCommand command)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// .. some code to do one set of update
await _myDbContext.SaveChangesAsync();
// .. some other db updates that need to be run separately
await _myDbContext.SaveChangesAsync();
scope.Complete();
}
}
}
Я думаю, что я действительно спрашиваю, создает ли вложенный вызов «BeginTransaction» новую транзакцию (эквивалентную «TransactionScopeOption.RequiresNew») или использует транзакцию с внешним использованием (эквивалентно «TransactionScopeOption.Required')? Помимо моей неспособности заставить ее работать, переход на «BeginTransaction» основывался на том, что это их рекомендация для EF6 +. Я открыт для того, чтобы заставить его работать с «TransactionScope», но если я открою соединение вручную, я получу исключение до завершения внешней транзакции (транзакция «завершена, но не была удалена») –
BeginTransaction как Требуется. Нет способа иметь несколько транс в одном соединении. Поэтому он не может вести себя как RequiresNew. 'будучи их рекомендацией для EF6', я тоже это читал, но я думаю, что никаких аргументов не было. Странный совет. 'Я получаю исключение до завершения внешней транзакции. Я думаю, вам следует исследовать и исправить ошибку. Зачем бросать весь подход, если все, что вам нужно сделать, это исправить небольшую ошибку? – usr
Отлично, я не знал, что у вас может быть только одна транзакция за соединение. Я просто не мог «TransactionScope» работать в моем сценарии, поэтому в итоге я написал небольшую абстракцию, которая означала, что у меня могут быть вложенные области транзакций и по-прежнему использовать «Database.BeginTransaction», чтобы открыть базовую транзакцию. Благодарим за помощь @usr –