c#-4.0 - Entity Framework Transactionscope - 不回滚第一个事务

标签 c#-4.0 asp.net-mvc-4 entity-framework-5

我正在尝试创建一个封装 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/

相关文章:

asp.net-mvc - Web API 模型绑定(bind)与 Multipart formdata

所有其他应用程序上的 C# 气球通知弹出窗口

c# - ASP NET MVC C# - .Model 是一个属性,但它像一个类型一样使用

c#-4.0 - Contract.Ensures 中的自定义方法

asp.net - 如何在部署时加密(连接字符串)webconfig?出于安全原因

c# - 如何从整数列表中设置选择元素的值和文本值

c# - 调用 SaveChanges 时出现奇怪的 DbEntityValidationException

entity-framework - 我们可以将现有实体用于 Entity Framework 而不是 EF 生成的实体吗

c# - context.SaveChanges() 在添加时出错

asp.net-mvc-4 - 将 MVC 4 SimpleMembership 与现有的数据库优先 EF 模型结合使用