I have the code below where I call a service to fetch data, then save the data in a list (transfers). Then I loop through each transfer to update a specific row in the DB.
QUESTIONS -
- Do I need to use a cancellation token on the transaction?
- If yes, what do I do if an db exception is thrown?
- Is this the best way to update a large number of rows (Ex. 500)?
var service = new BalanceTransactionService();
var transfers = new List<(string, decimal?, long, string, string)>();
await foreach (BalanceTransaction balTransaction in service.ListAutoPagingAsync(listOptions, requestOptions))
{
var charge = (Stripe.Charge)balTransaction.Source;
transfers.Add((charge.SourceTransferId, balTransaction.ExchangeRate, balTransaction.Amount, balTransaction.Currency, stripePayoutId));
}
CancellationToken cancellationToken = new CancellationToken();
using var transaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);
try
{
foreach (var transfer in transfers)
{
var stripeTransfersResult = await _dbContext.StripeTransfers
.Where(p => p.TransferId == transfer.Item1)
.ExecuteUpdateAsync(setters => setters
.SetProperty(p => p.ExchangeRate, transfer.Item2)
.SetProperty(p => p.ExchangeAmount, transfer.Item3)
.SetProperty(p => p.ExchangeCurrency, transfer.Item4)
.SetProperty(p => p.StripePayoutId, transfer.Item5)
.SetProperty(p => p.EditedDate, DateTime.UtcNow)
);
}
await transaction.CommitAsync(cancellationToken);
}
catch (DbException ex)
{
// rollback if error
await transaction.RollbackAsync(cancellationToken);
_logger.LogInformation("Results not saved when associating payout with transfers. Stripe Payout Id: " + stripePayoutId);
_emailService.SendEmailMessage(EmailType.Exceptions, "ReconcileTransferQueue Exception", "Exception thrown when associating payout with transfers. <br> Stripe Payout Id: " + stripePayoutId + "<br> Exception: <br>" + ex.ToString(), true);
}
StripeTransfersobjects, a singleSaveChangesat the end would actually persisting all changes in a single transaction. Unlike the rest of EF,ExecuteUpdateAsyncandExecuteDeleteAsyncacts as little more than SQL generators.