public async virtual Task <int> AddItems(params Item[] items) { _ctx.Items.AddRange(items); var transaction = new AppTransaction(); _ctx.Transactions.Add(transaction); int result = 0; var strategy = _ctx.Database.CreateExecutionStrategy(); try { Debug.WriteLine(_ctx.Entry(transaction).State);//Added strategy.ExecuteInTransaction( operation: () => { result = _ctx.SaveChanges(); throw new ConnectionAbortedException(); }, verifySucceeded: () => _ctx.Transactions.AsNoTracking().Any(t => t.Id == transaction.Id) ); }catch (Exception ex) { Debug.WriteLine(_ctx.Entry(transaction).State);//Unchanged } return(result); }
public RatesController( AppTransaction tx, IMapper mapper, RateRepository rateRepository, BoardGameRepository boardGameRepository, UserManager <User> userManager ) { TX = tx; _mapper = mapper; _rateRepository = rateRepository; _userManager = userManager; _boardGameRepository = boardGameRepository; }
public async virtual Task <Item> AddItem(Item item) { //using (var transaction = new TransactionScope()) //Ошибка при выбранной стратегии устойчевого выполнения //{ // await _ctx.Items.AddAsync(item); // await _ctx.SaveChangesAsync(); // transaction.Complete(); //} var strategy = _ctx.Database.CreateExecutionStrategy(); //Можно создать без opt => opt.EnableRetryOnFailure() в конфигурцаии UseSqlServer //Решение 1 //Но не учтена ошибка при фиксации транзакции (напр. прерывание соединения, а данные уже сохранены в бд) //await strategy.Execute(async () => //{ // using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) // { // await _ctx.Items.AddAsync(item); // await _ctx.SaveChangesAsync(); // //Здесь поток уже может быть другим // transaction.Complete(); // } //}); //Решение 2 без явного вызова транзакции и с проверкой достоврености транзакции //Этот вызов можно включить в переопределение метода SaveChanges контекста AppTransaction transaction = new AppTransaction(); await _ctx.Items.AddAsync(item); await _ctx.Transactions.AddAsync(transaction); strategy.ExecuteInTransaction(_ctx, operation: (context) => { context.SaveChanges(acceptAllChangesOnSuccess: false); //ChangeTracking не участвует в откате транзакции }, verifySucceeded: context => //Вызывается в случае определенной ошибки в первом делегате. Может быть не вызван { //Если false - можно описать логику возвращения состояния контекста до очередного запуска транзакции return(context.Transactions.AsNoTracking().Any(t => t.Id == transaction.Id)); }); //Если выполнения дойдет сюда - значит все сохранено успешно _ctx.ChangeTracker.AcceptAllChanges(); _ctx.Transactions.Remove(transaction); _ctx.SaveChanges(); return(item); }