代码之家  ›  专栏  ›  技术社区  ›  Learning-Overthinker-Confused

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

  •  1
  • Learning-Overthinker-Confused  · 技术社区  · 8 年前

    这是我的桌子:

    大学生 : 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 回复  |  直到 8 年前
        1
  •  1
  •   Ivan Stoev    8 年前

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

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

    正在查看 Retrieving Identity or Autonumber Values 主题中,实际上您基本上需要手动生成insert命令。

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

    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();
    }  
    
        2
  •  1
  •   user47589 user47589    8 年前

    当您进行第一次更新时,该行被写入数据库,并根据 AUTOINCREMENT 。但是 DataTable 不会反映更改后的ID。因此,当您尝试进行第二次更新时,它找不到要更新的行(数据表中的ID与数据库中的ID不匹配)。因此,会出现并发错误。

    这就是为什么,为了将ID输入 数据表 ,您需要刷新 数据表 在进行第二次更新之前。

    要刷新 数据表 ,呼叫:

    adapter.Fill()
    

    有关更多信息,请阅读 Merging DataSet Contents .