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

如何用DataGrid添加值更新数据库?删除行时更新库报错求解

解决DataGrid与数据库同步的两个问题

问题1:通过DataGrid添加特定值更新数据库

假设你用的是WinForms/WPF中最常用的ADO.NET + DataTable绑定场景,这里提供两种可靠的实现方式:

  • 第一步:确保DataGrid绑定的是可更新数据源,比如DataTable(而非只读集合),绑定代码示例:
    DataTable salesTable = new DataTable();
    // 从数据库初始化数据表,比如用SqlDataAdapter.Fill(salesTable)
    dataGridSales.DataSource = salesTable;
    
  • 第二步:同步新增行到数据库
    • 方法一:利用SqlDataAdapter自动处理更新
      提前配置好Insert命令,后续直接调用Update方法即可自动识别新增行并执行SQL:
      // 初始化Insert命令(需替换为你的表字段和参数)
      SqlCommand insertCmd = new SqlCommand(
          "INSERT INTO Sales (ProductName, Quantity, SaleDate) VALUES (@Name, @Qty, @Date)", 
          yourDbConnection);
      insertCmd.Parameters.Add("@Name", SqlDbType.VarChar, 100, "ProductName");
      insertCmd.Parameters.Add("@Qty", SqlDbType.Int, 0, "Quantity");
      insertCmd.Parameters.Add("@Date", SqlDbType.DateTime, 0, "SaleDate");
      
      SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Sales", yourDbConnection);
      adapter.InsertCommand = insertCmd;
      
      // 当需要同步时调用(比如用户点击保存按钮)
      adapter.Update(salesTable);
      
    • 方法二:手动捕获新增事件执行SQL
      监听DataGridView.RowsAdded事件,获取新增行的值后直接执行INSERT:
      private void dataGridSales_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
      {
          DataGridViewRow newRow = dataGridSales.Rows[e.RowIndex];
          // 跳过DataGrid自带的空白新行
          if (newRow.IsNewRow) return;
          
          // 提取行中特定值
          string productName = newRow.Cells["ProductName"].Value.ToString();
          int quantity = Convert.ToInt32(newRow.Cells["Quantity"].Value);
          DateTime saleDate = Convert.ToDateTime(newRow.Cells["SaleDate"].Value);
          
          // 执行数据库插入
          using (SqlConnection conn = new SqlConnection(yourConnString))
          {
              conn.Open();
              string sql = "INSERT INTO Sales (ProductName, Quantity, SaleDate) VALUES (@Name, @Qty, @Date)";
              SqlCommand cmd = new SqlCommand(sql, conn);
              cmd.Parameters.AddWithValue("@Name", productName);
              cmd.Parameters.AddWithValue("@Qty", quantity);
              cmd.Parameters.AddWithValue("@Date", saleDate);
              cmd.ExecuteNonQuery();
          }
      }
      

问题2:删除DataGrid行时无法更新数据库的问题

你提到用RowsRemoved报错是正常的——这个事件触发时,行已经从DataGrid中被移除,自然无法获取值。改用UserDeletingRow是正确的方向,大概率是你的代码没处理好这几个关键点:

核心修复方案

private void dataGridSales_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
    // 1. 先判断是否是未保存的新行(这类行不需要操作数据库)
    if (e.Row.Cells["SalesID"].Value == DBNull.Value)
    {
        e.Cancel = true; // 取消删除,或直接允许界面移除(根据需求调整)
        MessageBox.Show("未保存的新增行无需同步数据库");
        return;
    }
    
    // 2. 获取待删除行的主键(必须在删除前获取!)
    int salesId = Convert.ToInt32(e.Row.Cells["SalesID"].Value);
    
    // 3. 执行数据库删除操作,加事务保证一致性
    try
    {
        using (SqlConnection conn = new SqlConnection(yourConnString))
        {
            conn.Open();
            using (SqlTransaction tran = conn.BeginTransaction())
            {
                try
                {
                    // 如果是需要增减库存的场景,先执行库存更新
                    string updateStockSql = "UPDATE Products SET Stock = Stock + @Qty WHERE ProductID = @ProdID";
                    SqlCommand updateCmd = new SqlCommand(updateStockSql, conn, tran);
                    updateCmd.Parameters.AddWithValue("@Qty", Convert.ToInt32(e.Row.Cells["Quantity"].Value));
                    updateCmd.Parameters.AddWithValue("@ProdID", Convert.ToInt32(e.Row.Cells["ProductID"].Value));
                    updateCmd.ExecuteNonQuery();
                    
                    // 再删除销售记录
                    string deleteSql = "DELETE FROM Sales WHERE SalesID = @SalesID";
                    SqlCommand deleteCmd = new SqlCommand(deleteSql, conn, tran);
                    deleteCmd.Parameters.AddWithValue("@SalesID", salesId);
                    int affectedRows = deleteCmd.ExecuteNonQuery();
                    
                    if (affectedRows == 0)
                    {
                        MessageBox.Show("数据库中无对应记录,取消删除");
                        tran.Rollback();
                        e.Cancel = true;
                        return;
                    }
                    
                    tran.Commit();
                }
                catch (Exception ex)
                {
                    tran.Rollback();
                    MessageBox.Show("删除失败:" + ex.Message);
                    e.Cancel = true; // 出错时取消界面删除,避免数据不一致
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("数据库连接失败:" + ex.Message);
        e.Cancel = true;
    }
}

关键注意点

  • 必须在删除前获取行数据:UserDeletingRow是删除动作触发前的最后时机,此时行还在DataGrid中,能正常读取值。
  • 处理未保存的新行:这类行只存在于界面,数据库中没有对应记录,无需执行SQL。
  • 用参数化查询:绝对避免SQL注入风险。
  • 事务包裹多步操作:如果删除销售记录同时要更新库存,必须用事务保证两步操作要么都成功,要么都回滚。

内容的提问来源于stack exchange,提问作者Jepher John Chang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:08:29