我正在尝试创建一个封装 4 个数据库表插入和 2 个更新的事务。
我“大部分时间”都在工作。我的意思是,如果我在这 6 个数据库交互中的任何一个出现错误,之前的回滚都会发生......除了第一个。第一个是插入到表头表...随后插入到明细表甚至另一个表头表等...全部回滚...但是如果回滚后您检查表,所有表都将没有记录,除了第一个。
//Create receipt, ic, printq; update pod, poh
public List<ActionConfirmation<int>> CreateReceipt(
IEnumerable<ReceiptDetailPalletListViewModel> viewModelList,
int intUserId,
int intFacilityId,
int intLocationId
)
{
var dbContext = new InventoryMgmtContext();
//Opening connection
dbContext.Database.Connection.Open();
int intReceiptHdrId = 0;
int intICHdrId = 0;
var results = new List<ActionConfirmation<int>>();
foreach (ReceiptDetailPalletListViewModel viewModel in viewModelList)
{
if (viewModel.ReceivedQty > 0)
{
using (TransactionScope transaction = new TransactionScope())
{
//Create Receipt Header
ActionConfirmation<int> rcptHdrResult = CreateReceiptHeader(
dbContext,
intUserId,
intFacilityId); <===== This Tran never rolls back. Insert occured.
results.Add(rcptHdrResult);
if (!rcptHdrResult.WasSuccessful) //Recp Hdr create failed.
{
CloseFailedTrans(dbContext, transaction);
return results;
}
intReceiptHdrId = rcptHdrResult.Value;
//Create new ICHeader
ActionConfirmation<int> icHdrResult = CreateICHeader(
dbContext,
intUserId,
intFacilityId,
intLocationId,
intReceiptHdrId
);
results.Add(icHdrResult);
if (!icHdrResult.WasSuccessful)
{
CloseFailedTrans(dbContext, transaction);
return results;
}
intICHdrId = icHdrResult.Value;
//Create new ICDetail
ActionConfirmation<int> icDtlResult = CreateICDetail(
dbContext,
intICHdrId,
viewModel.ItemId,
viewModel.PODetailId,
viewModel.ReceivedQty,
intUserId
);
results.Add(icDtlResult);
if (!icDtlResult.WasSuccessful)
{
CloseFailedTrans(dbContext, transaction);
return results;
}
//Create new Recpt Detail
ActionConfirmation<int> rcptDtlResult = CreateReceiptDetail(
dbContext,
intReceiptHdrId,
viewModel.PODetailId,
viewModel.ReceivedQty,
intUserId
);
results.Add(rcptDtlResult);
if (!rcptDtlResult.WasSuccessful)
{
CloseFailedTrans(dbContext, transaction);
return results;
}
//Update PO Detail qty and Header status
List<ActionConfirmation<int>> poResults = UpdatePODetail(
dbContext,
viewModel.PODetailId,
viewModel.ReceivedQty,
intUserId
);
foreach (ActionConfirmation<int> poResult in poResults)
{
results.Add(poResult);
if (!poResult.WasSuccessful)
{
CloseFailedTrans(dbContext, transaction);
return results;
}
}
//Create new Print Q
ActionConfirmation<int> printqResult = CreatePrintQRecords(
dbContext,
intICHdrId,
intFacilityId,
intUserId
);
results.Add(printqResult);
if (!printqResult.WasSuccessful)
{
CloseFailedTrans(dbContext, transaction);
return results;
}
//Everything inserted correctly
CloseSuccessTrans(dbContext, transaction);
} //using statement
} //if rcv qty > 0
} // for each loop
dbContext.Database.Connection.Dispose();
return results;
}
以下是交易相关方法:
// Close DB Connections and transaction
private void CloseFailedTrans(InventoryMgmtContext dbContext, TransactionScope transaction)
{
//TODO: logging
CloseTrans(dbContext, transaction);
}
// Close DB Connections and transaction
private void CloseSuccessTrans(InventoryMgmtContext dbContext, TransactionScope transaction)
{
transaction.Complete();
CloseTrans(dbContext, transaction);
}
// Close DB Connections and transaction
private void CloseTrans(InventoryMgmtContext dbContext, TransactionScope transaction)
{
transaction.Dispose();
}
下面是执行插入的方法之一的示例。它们都遵循相同的模式:
//Create Receipt Header
private ActionConfirmation<int> CreateReceiptHeader(
InventoryMgmtContext dbContext,
int intUserId,
int intFacilityId
)
{
//var repository = new Repository<ReceiptHeader>(dbContext);
var repository = new ReceiptHeaderRepository(dbContext);
//Create new Receipt Header
ReceiptHeader rcptHdr = new ReceiptHeader()
{
FacilityId = intFacilityId,
StatusId = 1,
CreatedById = intUserId,
CreatedOn = DateTime.Now,
ModifiedById = intUserId,
ModifiedOn = DateTime.Now
};
return repository.Insert(rcptHdr);
}
这是存储库插入方法:
public virtual ActionConfirmation<int> Insert(TRepository entity)
{
try
{
_dataContext.Entry(entity).State = System.Data.EntityState.Added;
_dataContext.SaveChanges();
return CRUDMessage(true, "saved", entity);
}
catch (Exception ex)
{
return CRUDMessage(false, "save", entity, ex);
}
}
最佳答案
您不需要TransactionScope
。只需在当前启动 TransactionScope
的位置创建一个新上下文即可。为了使其正常工作,您需要删除多个退出点(return
)并仅在最后调用一次SaveChanges()
并捕获异常。这也将清理您的代码并使其更好地可维护(多个退出点被视为反模式)。
只有SaveChanges()
,而不是其他任何东西,将更改提交到数据库。 SaveChanges()
管理自己的事务:它保存全部,或者不保存。
关于c#-4.0 - Entity Framework Transactionscope - 不回滚第一个事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14508591/