You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL售后系统取消订单异常:重复添加而非删除记录求助

问题排查与解决方案

核心问题分析

从提供的代码来看,当前取消订单的逻辑完全没有执行删除销售历史记录的操作,反而可能通过SaveCancelOrder(user)方法重复添加了记录,仅完成了库存和购物车数量的恢复(这部分逻辑本身合理,但缺少关键的删除/标记取消步骤)。

具体问题点

  1. 缺失销售记录处理逻辑:代码中没有任何针对销售历史表(如tbSoldHistory)的DELETE或状态更新语句,这是销售记录未被删除的直接原因。
  2. SaveCancelOrder(user)方法逻辑反向:这个方法的命名虽带"Cancel",但实际可能是将取消的订单数据重新插入到销售历史表,而非处理原订单,导致重复添加记录。
  3. SQL语句存在注入风险:所有ExecuteQuery的SQL均为字符串拼接,易引发语法错误,且存在严重SQL注入漏洞。
  4. 资源释放不严谨:数据库连接和数据阅读器的关闭逻辑存在隐患(如分支判断可能导致dr.Close()或cn.Close()未执行)。

修复步骤

1. 修正SaveCancelOrder(user)方法

打开该方法实现,检查并调整逻辑:

  • 如果它是在插入新销售记录,直接删除该逻辑,替换为删除原订单或标记原订单为已取消(推荐软删除,保留历史数据)。
  • 软删除示例:
    private void SaveCancelOrder(string user)
    {
        // 标记原订单为已取消,而非插入新记录
        dbcon.ExecuteQuery(
            "UPDATE tbSoldHistory SET is_cancelled = 1, cancelled_by = @user WHERE order_id = @orderId",
            new SqlParameter("@user", user),
            new SqlParameter("@orderId", cancelOrder.txtId.Text)
        );
    }
    
    硬删除示例:
    private void SaveCancelOrder(string user)
    {
        dbcon.ExecuteQuery(
            "DELETE FROM tbSoldHistory WHERE order_id = @orderId",
            new SqlParameter("@orderId", cancelOrder.txtId.Text)
        );
    }
    

2. 补充销售记录处理逻辑

如果SaveCancelOrder原本不负责处理销售记录,需在代码中添加对应操作,比如在SaveCancelOrder(user)之后添加:

// 软删除(推荐)
dbcon.ExecuteQuery(
    "UPDATE tbSoldHistory SET status = 'Cancelled', cancelled_by = @user WHERE id = @id",
    new SqlParameter("@user", user),
    new SqlParameter("@id", cancelOrder.txtId.Text)
);

// 或硬删除
// dbcon.ExecuteQuery("DELETE FROM tbSoldHistory WHERE id = @id", new SqlParameter("@id", cancelOrder.txtId.Text));

3. 修复SQL注入问题

将所有字符串拼接的SQL改为参数化查询,比如原库存更新语句:

// 原错误写法
// dbcon.ExecuteQuery("UPDATE tbProduct SET qty = qty + " + cancelOrder.udCancelQty.Value + " where pcode= '" + cancelOrder.txtPcode.Text + "'");

// 参数化写法
var updateProductCmd = new SqlCommand(
    "UPDATE tbProduct SET qty = qty + @cancelQty WHERE pcode = @pcode", 
    dbcon.GetConnection()
);
updateProductCmd.Parameters.AddWithValue("@cancelQty", cancelOrder.udCancelQty.Value);
updateProductCmd.Parameters.AddWithValue("@pcode", cancelOrder.txtPcode.Text);
updateProductCmd.ExecuteNonQuery();

4. 优化资源释放

用using语句自动管理数据库资源,避免泄漏:

private void btnVoid_Click(object sender, EventArgs e)
{
    try
    {
        if (txtUsername.Text.ToLower() == cancelOrder.txtCancelBy.Text.ToLower())
        {
            MessageBox.Show("Void by name and cancelled by name are same!. Please void by another person.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            return;
        }

        string user = null;
        using (var cn = new SqlConnection(yourConnectionString)) // 替换为你的数据库连接字符串
        {
            cn.Open();
            using (var cm = new SqlCommand("Select username From tbUser Where username = @username and password = @password", cn))
            {
                cm.Parameters.AddWithValue("@username", txtUsername.Text);
                cm.Parameters.AddWithValue("@password", txtPass.Text);
                using (var dr = cm.ExecuteReader())
                {
                    if (dr.Read())
                    {
                        user = dr["username"].ToString();
                    }
                }
            }
        }

        if (!string.IsNullOrEmpty(user))
        {
            SaveCancelOrder(user);
            
            if(cancelOrder.cboInventory.Text == "yes")
            {
                var updateProductCmd = new SqlCommand(
                    "UPDATE tbProduct SET qty = qty + @cancelQty WHERE pcode = @pcode", 
                    dbcon.GetConnection()
                );
                updateProductCmd.Parameters.AddWithValue("@cancelQty", cancelOrder.udCancelQty.Value);
                updateProductCmd.Parameters.AddWithValue("@pcode", cancelOrder.txtPcode.Text);
                updateProductCmd.ExecuteNonQuery();
            }

            var updateCartCmd = new SqlCommand(
                "UPDATE tbCart SET qty = qty + @cancelQty WHERE id = @id", 
                dbcon.GetConnection()
            );
            updateCartCmd.Parameters.AddWithValue("@cancelQty", cancelOrder.udCancelQty.Value);
            updateCartCmd.Parameters.AddWithValue("@id", cancelOrder.txtId.Text);
            updateCartCmd.ExecuteNonQuery();

            MessageBox.Show("Order transaction successfully cancelled!", "Cancel Order", MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.Dispose();
            cancelOrder.ReloadSoldList();
            cancelOrder.Dispose();
        }
        else
        {
            MessageBox.Show("Invalid username or password!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }
}

额外建议

  • 优先使用软删除(标记状态),保留完整订单历史,便于后续排查和统计。
  • 对数据库操作添加事务管理,确保库存更新、订单状态更新等操作要么全部成功,要么全部回滚,避免数据不一致。

内容的提问来源于stack exchange,提问作者Agili

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 12:26:33