private void TryMakeTransaction(Transaction transactionDto, int attemptNumber) { var senderAccount = _accountRepository.SingleOrDefault(c => c.UserId == transactionDto.SenderId); Account receiverAccount = null; int transactionDirection = 1; using (var transaction = _accountRepository.BeginTransaction()) { try { switch (transactionDto.Type) { case TransactionType.Withdraw: transactionDirection = -1; break; case TransactionType.Transfer: receiverAccount = _accountRepository.SingleOrDefault(c => c.UserId == transactionDto.ReceiverId); receiverAccount.Balance += transactionDto.Amount; transactionDirection = -1; _accountRepository.Update(receiverAccount); break; } senderAccount.Balance += transactionDto.Amount * transactionDirection; _transactionRepository.Add(new Domain.Transaction() { SenderAccountId = senderAccount.AccountId, Amount = transactionDto.Amount, ReceiverAccountId = receiverAccount?.AccountId, Type = transactionDto.Type }); _accountRepository.Update(senderAccount); _accountRepository.SaveChanges(); transaction.Commit(); } catch (Exception e) { transaction.Rollback(); _accountRepository.DetachAllEntities(); if (e is DbUpdateConcurrencyException && attemptNumber < _attemptsCount) { TryMakeTransaction(transactionDto, ++attemptNumber); } else { throw new Exception("Sorry, your transaction was canceled! Try again later"); } } } }
public void MakeTransaction(Transaction transactionDto) { TryMakeTransaction(transactionDto, 0); }