C# 如何在不同的方法中执行两个SQL命令,并在第二个命令引发异常时回滚

C# 如何在不同的方法中执行两个SQL命令,并在第二个命令引发异常时回滚,c#,asp.net,sql-server,ado.net,n-layer,C#,Asp.net,Sql Server,Ado.net,N Layer,我很难解释这个问题。但也许我能在这里做得更好 在我的4层体系结构应用程序中,一个带有仓库管理系统(一个简单的系统)但有很多业务规则的在线商店 例1: 表示层调用业务层保存产品 BL.SaveProduct方法调用DL.SaveProduct然后调用DL.DecreaseBalance方法 如果在DL.DecreaseBalance中发生异常,则产品将违反业务规则保存,如果我不能通过让DL处理这两个事务来违反SoC,则产品将被保存 有没有一种设计模式或技巧可以帮助解决这个问题 我的BL方法

我很难解释这个问题。但也许我能在这里做得更好

在我的4层体系结构应用程序中,一个带有仓库管理系统(一个简单的系统)但有很多业务规则的在线商店

例1:

  • 表示层
    调用
    业务层
    保存
    产品
  • BL.SaveProduct
    方法调用
    DL.SaveProduct
    然后调用
    DL.DecreaseBalance
    方法
  • 如果在
    DL.DecreaseBalance
    中发生异常,则产品将违反业务规则保存,如果我不能通过让DL处理这两个事务来违反SoC,则产品将被保存

    有没有一种设计模式或技巧可以帮助解决这个问题

    我的BL方法

        public static bool CreateProduct(Product Product, out string Message)
        {
            using (TransactionScope transactionScope = new TransactionScope())
            {
                try
                {
                    //validate
                    if (Product.ValidateNew(out Message))
                    {
                        //Check if sufficient balance exists
                        if (ProductBulksBL.BulkHasEnoughBalance(Product.BulkID, 1))
                        {
                            //save
                            ProductsDAL.CreateProduct(Product, out Message);
    
                                //log
                                ProductCreationLogDTO pLog = new ProductCreationLogDTO();
                                pLog.BulkID = Product.BulkID;
                                pLog.CreatedBy = UsersDAL.GetCurrentUserID();
                                pLog.TimeCreated = DateTime.Now;
    
                                ProductsDAL.LogCreatedProduct(pLog, out Message);
    
                                    //update bulk balance 
                                    ProductBulksDAL.UpdateBulkBalance(Product.BulkID, 1);
                                    return true;
                        }
                        else
                        {
                            Message = "This product bulks doesn't have enough balance";
                            return false;
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
                catch (TransactionException ex)
                {
                    Message = ex.Message;
                    transactionScope.Dispose();
                    return false;
                }
                finally
                {
                    transactionScope.Complete();
                    transactionScope.Dispose();
                }
            }
        }
    
    使用相同方法构建的示例DL方法

        public static void CreateProduct(Product Product, out string Message)
        {
            using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
            {
                using (SqlCommand cmd = new SqlCommand("INSERT INTO Products (BulkID, CountryID, CityID, AreaID, Price, [Description], IPBan) VALUES (@BulkID, @CountryID, @CityID, @AreaID, @Price, @Description, @IPBan) ", conn))
                {
                    cmd.Parameters.AddWithValue("@BulkID", Product.BulkID);
                    cmd.Parameters.AddWithValue("@Price", Product.Price);
                    cmd.Parameters.AddWithValue("@Description", Product.Description);
                    cmd.Parameters.AddWithValue("@IPBan", Product.IPBan);
    
                    if (Product.Country != null)
                        cmd.Parameters.AddWithValue("@CountryID", Product.Country.ID);
                    else
                        cmd.Parameters.AddWithValue("@CountryID", DBNull.Value);
    
                    if (Product.City != null)
                        cmd.Parameters.AddWithValue("@CityID", Product.City.ID);
                    else
                        cmd.Parameters.AddWithValue("@CityID", DBNull.Value);
    
                    if (Product.Area != null)
                        cmd.Parameters.AddWithValue("@AreaID", Product.Area.ID);
                    else
                        cmd.Parameters.AddWithValue("@AreaID", DBNull.Value);
    
                        conn.Open();
                        cmd.ExecuteNonQuery();
    
                        Message = "";
                }
            }
        }
    

    TransactionScope不工作

    数据库事务?将两个调用放入
    System.transaction.TransactionScope
    中,并且仅在两个调用都成功时提交-否则回滚是。实际上,我曾经在一个sql事务对象内的同一个方法中运行两个sql语句,以便在出现异常时回滚。但是现在我在看它的设计,它违反了SoC,并且实际上在将来很难修改业务规则。所以我也希望做同样的事情,但是回滚一个方法,而不是回滚一个sql命令mean@marc_s,我以前没听说过。但从名字来看,这可能是解决我问题的完美方法。我会看看如何实现它,然后再给你回复。Thanks@marc_s,我编辑了我的帖子,包括我是如何实现它的。我在创建产品后调用的第二个方法中有一个异常。产品已创建,但应用程序不会回滚。