使用数据适配器更新记录时出现并发错误

时间:2016-06-20 14:10:11

标签: c# .net datatable ado.net dataadapter

这是我的表:

学生StudentId int PK autoincrement,Name varchar(20)

当我尝试更新上次添加的记录时,我发现错误:

错误Concurrency violation: the UpdateCommand affected 0 of the expected 1 records.

这是我的代码:

using (var connection = new SqlConnection("MyConnectionstring"))
            {
                connection.Open();
                SqlDataAdapter adapter = new SqlDataAdapter();
                SqlCommandBuilder builder = new SqlCommandBuilder(adapter);

                adapter.SelectCommand = new SqlCommand("select * from Student", connection);


                DataTable dt = new DataTable();
                adapter.Fill(dt);

                DataRow row = dt.NewRow();
                row["Name"] = "Abc";
                dt.Rows.Add(row);
                var addedRecords = dt.GetChanges(DataRowState.Added);
                adapter.Update(dt);
                dt.AcceptChanges();
                DataRow lastRow = dt.Rows[dt.Rows.Count - 1];

                row["Name"] = "Pqr";
                adapter.Update(dt); //Error Here
                connection.Close();
            }  

有人可以告诉我为什么会发生这种情况以及这个问题的解决方法是什么?

2 个答案:

答案 0 :(得分:1)

当您执行第一次更新时,该行将写入数据库,并根据AUTOINCREMENT获取主键。但是,DataTable中的行不会反映更改的ID。因此,当您尝试执行第二次更新时,它无法找到您要更新的行(数据表中的ID与数据库中的ID不匹配)。因此,您会收到并发错误。

这就是为什么,为了将ID加入DataTable,您需要在进行第二次更新之前刷新DataTable的内容。

要刷新DataTable,请致电:

adapter.Fill()

有关详情,请参阅Merging DataSet Contents

答案 1 :(得分:1)

Generating Commands with CommandBuilders MSDN主题中所述,命令构建器生成的自动命令不会检索插入记录的标识字段:

  

您可能希望将输出参数映射回DataSet的更新行。一个常见任务是从数据源检索自动生成的标识字段或时间戳的值。默认情况下,DbCommandBuilder 不会将输出参数映射到更新行中的列。在这种情况下,您必须明确指定您的命令。

查看Retrieving Identity or Autonumber Values主题,结果证明基本上您需要手动生成插入命令。

以下是如何为表格执行此操作(请参阅代码中的注释):

using (var connection = new SqlConnection("MyConnectionstring"))
{
    connection.Open();

    // Create data adapter with the specified SelectCommand
    var adapter = new SqlDataAdapter("select * from Student", connection);

    // Build InsertCommand    
    var insertCommand = new SqlCommand(
        "insert into Student (Name) values (@Name) SET @Id = SCOPE_IDENTITY()", 
        connection);
    insertCommand.Parameters.Add("@Name", SqlDbType.VarChar, 20, "Name");
    var parameter = insertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "StudentId");
    parameter.Direction = ParameterDirection.Output;
    insertCommand.UpdatedRowSource = UpdateRowSource.OutputParameters;
    adapter.InsertCommand = insertCommand;

    // Auto build outher commands
    var builder = new SqlCommandBuilder(adapter);

    // Read the data
    var dt = new DataTable();
    adapter.Fill(dt);

    // Insert a new record
    var row = dt.NewRow();
    row["Name"] = "Abc";
    dt.Rows.Add(row);

    adapter.Update(dt);

    // Update the just inserted record
    row["Name"] = "Pqr";
    adapter.Update(dt);

    connection.Close();
}