每个DataGridView行的C#更新数据库

时间:2016-02-01 08:07:44

标签: c# datagridview

我想使用Update按钮为DataGridView中的每一行更新数据库中的表。这是以下更新按钮代码:

private void btUpdate_Click(object sender, EventArgs e)
{
    SqlConnection cn = new SqlConnection(con);
    cn.Open();
    SqlCommand cmdUpdate = new SqlCommand("UPDATE OINV SET U_IDU_HFP = @HFP, U_IDU_FAKTURPAJAK = @FP, U_IDU_FPDATE = @FPDATE WHERE DocEntry = @DocEntry;", cn);
    foreach (DataGridViewRow item in dgvInputPKP.Rows)
    {
        cmdUpdate.Parameters.AddWithValue("@HFP", item.Cells[10].Value);
        cmdUpdate.Parameters.AddWithValue("@FP", item.Cells[11].Value);
        cmdUpdate.Parameters.AddWithValue("@FPDATE", item.Cells[9].Value);
        cmdUpdate.Parameters.AddWithValue("@DocEntry", item.Cells[1].Value);
        cmdUpdate.ExecuteNonQuery();
    }
    MessageBox.Show("Record Updated Successfully");
    cn.Close();
}

当我按下更新按钮时,只有DataGridViews的第一行在数据库中显示 ,而不是其他行。 它还会返回一些错误,包括以下细节:

  

变量名称' @ HFP'已经宣布。变量名在查询批处理或存储过程中必须是唯一的。

我试图搜索和谷歌搜索,但从来没有找到合适的。

请帮我解决这个问题。 感谢。

3 个答案:

答案 0 :(得分:2)

您需要在每个循环中清除Command.Parameters集合

foreach (DataGridViewRow item in dgvInputPKP.Rows)
{
    cmdUpdate.Parameters.Clear();
    ....
    cmdUpdate.ExecuteNonQuery();
}

但是,这里可以做一些事情来优化并使您的代码更安全并消除弱点。

using(SqlConnection cn = new SqlConnection(con))
using(SqlCommand cmdUpdate = new SqlCommand("UPDATE OINV SET U_IDU_HFP = @HFP, U_IDU_FAKTURPAJAK = @FP, U_IDU_FPDATE = @FPDATE WHERE DocEntry = @DocEntry;", cn))
{
    cn.Open();
    using(SqlTransaction tr = cn.BeginTrasaction())
    {
        cmdUpdate.Transaction = tr;
        cmdUpdate.Parameters.Add("@HFP", SqlDbType.NVarChar);
        cmdUpdate.Parameters.Add("@FP", SqlDbType.NVarChar);
        cmdUpdate.Parameters.Add("@FPDATE", SqlDbType.NVarChar);
        cmdUpdate.Parameters.Add("@DocEntry", SqlDbType.NVarChar);
        foreach (DataGridViewRow item in dgvInputPKP.Rows)
        {
            cmdUpdate.Parameters["@HFP"].Value = item.Cells[10].Value;
            cmdUpdate.Parameters["@FP"].Value = item.Cells[11].Value;
            cmdUpdate.Parameters["@FPDATE"].Value = item.Cells[9].Value;
            cmdUpdate.Parameters["@DocEntry"].Value = item.Cells[1].Value;
            cmdUpdate.ExecuteNonQuery();
       }
       tr.Commit();
   }
}
MessageBox.Show("Record Updated Successfully");

参数集合可以在进入循环之前声明,而在循环内部只更新值。另请注意,命令和连接是一次性对象,应在using块中声明和初始化。另外,为了使代码更加健壮,我添加了一个事务,确保将所有记录写入数据库,否则在发生故障时不会写入任何记录。循环结束时的SqlTransaction.Commit确保了这一点。

最后,我不知道接收参数值的字段的数据类型。您需要根据数据表中列的数据类型在创建参数时更改SqlDbType。

答案 1 :(得分:1)

由于您使用AddWithValue,此方法会尝试在每次迭代中反复添加参数及其值。

这就是你的第一次迭代工作的原因,但是在你的第二次迭代中你的命令已经具有那些参数定义,你仍然会尝试再次添加它们。并且您收到此错误消息。

只需在foreach statemnet上使用SqlParameterCollection.Clear方法,例如;

foreach (DataGridViewRow item in dgvInputPKP.Rows)
{
    cmdUpdate.Parameters.Clear();
    cmdUpdate.Parameters.AddWithValue("@HFP", item.Cells[10].Value);
    cmdUpdate.Parameters.AddWithValue("@FP", item.Cells[11].Value);
    cmdUpdate.Parameters.AddWithValue("@FPDATE", item.Cells[9].Value);
    cmdUpdate.Parameters.AddWithValue("@DocEntry", item.Cells[1].Value);
    cmdUpdate.ExecuteNonQuery();
}

顺便说一句,不要尽可能多地使用AddWithValueIt may generate unexpected and surprising results sometimes。使用Add方法重载来指定参数类型及其大小。

还可以使用using statement自动处理您的连接和命令,而不是手动调用CloseDispose方法。

答案 2 :(得分:0)

将整个SQL命令放在foreach中。