I've got a method which removes quantity from inventory when an order is completed. If there is not enough inventory quantity available, the order completion fails and the sql transaction is rolled back. Otherwise, transaction is commited.
I'm using Dapper for MySQL database access
public async Task<(bool, string)> CompleteInvoice(Invoice invoice, List<InvoiceLineItem> lineItems)
{
bool success = true;
string errorProductNumber = null;
if (!await UpdateInvoiceLineItemsAsync(lineItems))
return (false, "Error saving line items. Please try again.");
//Check to see if there is available quantity
using (var conn = _InvoiceRepository.DbConnection)
{
conn.Open();
// create the transaction
using (var trans = conn.BeginTransaction(System.Data.IsolationLevel.RepeatableRead))
{
try
{
var selectProductSQL = "SELECT InventoryNumber,Quantity FROM Product WHERE Id = @productId";
var updateProductSQL = "UPDATE Product SET Quantity = @NewQuantity WHERE Id = @productId";
DynamicParameters productParameters;
foreach (var lineItem in lineItems)
{
productParameters = new();
productParameters.Add("productId", lineItem.ProductId, System.Data.DbType.String);
var cprod = await conn.QueryFirstOrDefaultAsync<Product>(selectProductSQL, productParameters, trans);
if (cprod.Quantity >= lineItem.Quantity)
{
productParameters.Add("NewQuantity", cprod.Quantity - lineItem.Quantity, System.Data.DbType.Int32);
if (await conn.ExecuteAsync(updateProductSQL, productParameters, trans) != 1)
{
success = false;
}
}
else
{
errorProductNumber = cprod.InventoryNumber;
success = false;
}
if (!success)
break;
}
if (success)
{
invoice.InvoiceStatus = "COMPLETE";
if (!await UpdateInvoiceAsync(invoice))
{
success = false;
errorProductNumber = "Error saving invoice";
}
}
// if it was successful, commit the transaction
if (success)
trans.Commit();
else
{
trans.Rollback();
}
}
catch (Exception ex)
{
// roll the transaction back
trans.Rollback();
// handle the error however you need to.
//throw;
}
}
}
return (success, errorProductNumber);
}
I'm open and any General feedback. Am I correctly using the SQL Transaction mechanism?(Also with Dapper?)
UpdateInvoiceAsync
outside of the transaction? \$\endgroup\$updateinvoice
or is it "automatic" since the transaction has been started? This wasn't clear in the dapper doc or I haven't found it yet. Looking for some guidance. I want it inside the transaction. \$\endgroup\$