使用数据适配器更新记录时出现并发错误
Getting concurrency error on updating record with data adapter
这是我的 table:
学生: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();
}
谁能告诉我为什么会这样,解决这个问题的方法是什么??
当您进行第一次更新时,该行将写入数据库并根据 AUTOINCREMENT
获得一个主键。但是,DataTable
中的行并未反映更改后的 ID。因此,当您尝试进行第二次更新时,它找不到您要更新的行(数据中的 ID table 与数据库中的 ID 不匹配)。因此,您会收到并发错误。
因此,为了将 ID 放入 DataTable
,您需要在进行第二次更新之前刷新 DataTable
的内容。
要刷新 DataTable
,调用:
adapter.Fill()
有关详细信息,请阅读 Merging DataSet Contents。
如 Generating Commands with CommandBuilders MSDN 主题中所述,命令构建器生成的自动命令不会检索插入记录的身份字段:
You might want to map output parameters back to the updated row of a DataSet. One common task would be retrieving the value of an automatically generated identity field or time stamp from the data source. The DbCommandBuilder will not map output parameters to columns in an updated row by default. In this instance you must specify your command explicitly.
查看Retrieving Identity or Autonumber Values主题,发现基本上您需要手动生成插入命令。
以下是如何为您的 table 执行此操作(请参阅代码中的注释):
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();
}
这是我的 table:
学生: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();
}
谁能告诉我为什么会这样,解决这个问题的方法是什么??
当您进行第一次更新时,该行将写入数据库并根据 AUTOINCREMENT
获得一个主键。但是,DataTable
中的行并未反映更改后的 ID。因此,当您尝试进行第二次更新时,它找不到您要更新的行(数据中的 ID table 与数据库中的 ID 不匹配)。因此,您会收到并发错误。
因此,为了将 ID 放入 DataTable
,您需要在进行第二次更新之前刷新 DataTable
的内容。
要刷新 DataTable
,调用:
adapter.Fill()
有关详细信息,请阅读 Merging DataSet Contents。
如 Generating Commands with CommandBuilders MSDN 主题中所述,命令构建器生成的自动命令不会检索插入记录的身份字段:
You might want to map output parameters back to the updated row of a DataSet. One common task would be retrieving the value of an automatically generated identity field or time stamp from the data source. The DbCommandBuilder will not map output parameters to columns in an updated row by default. In this instance you must specify your command explicitly.
查看Retrieving Identity or Autonumber Values主题,发现基本上您需要手动生成插入命令。
以下是如何为您的 table 执行此操作(请参阅代码中的注释):
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();
}