在datatable中新增记录后,马上修改,就会报错
在datatable中新增记录后,马上修改,就会报如下错误
“违反并发性: UpdateCommand 影响了预期 1 条记录中的 0 条。”
如果修改旧的数据则不报错。
Material表创建语句
CREATE TABLE [Material] (
[i] [int] IDENTITY (1, 1) NOT NULL ,
[ID] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL ,
[Name] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
CONSTRAINT [PK_Material] PRIMARY KEY CLUSTERED
(
[ID]
) ON [PRIMARY]
) ON [PRIMARY]
代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace testUpdate
{
public partial class Form1 : Form
{
private SqlConnection nSqlcon;
private DataSet nds;
private DataTable ndt;
private DataRow ndr;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//打开表
string strSql="Server=.;Database=weight;Uid=sa;Pwd=123";
nSqlcon = new SqlConnection(strSql);
nSqlcon.Open();
strSql = "select * from material order by id";
SqlDataAdapter sda = new SqlDataAdapter(strSql, nSqlcon);
nds = new DataSet();
sda.Fill(nds);
ndt= nds.Tables[0];
dataGridView1.DataSource = ndt;
}
private void button1_Click(object sender, EventArgs e)
{
//新增一条记录
ndr = ndt.NewRow();
ndr["ID"] = "1001";
ndr["Name"] = "TEST";
ndt.Rows.Add(ndr);
SqlDataAdapter sda = new SqlDataAdapter();
SqlCommand scmd = new SqlCommand("select * from material order by id", nSqlcon);
sda.SelectCommand = scmd;
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
sda.Update(ndt);
}
private void button2_Click(object sender, EventArgs e)
{
//修改一条记录
ndr = ndt.Rows[dataGridView1.SelectedRows[0].Index];
ndr.BeginEdit();
ndr["Name"] = "TEST2";
ndr.EndEdit();
SqlDataAdapter sda = new SqlDataAdapter();
SqlCommand scmd = new SqlCommand("select * from material order by id", nSqlcon);
sda.SelectCommand = scmd;
SqlCommandBuilder scb = new SqlCommandBuilder(sda);
sda.Update(ndt);
}
}
}
数据 并发
[解决办法]
新增每条记录,需要程序先判断datatable中是否主键字段已有该值,可用table.select判断,然后读取判断结果的length是否为0,如果没有该值出现,则可以新增一条记录,并赋值主键,然后update。
[解决办法]
原因是:第一次新增时,本机内存中的datatable把新增记录各字段值update给 SQL Server, SQL Server 保存同时自动赋值id,但是该id并没有返回内存中的datatable,因此datatable中的这条记录是没有主键值的,此时如果程序又要修改该条记录,并想再次提交保存,此时 SQL Server 接到该记录的修改信息,但里面没有主键值, SQL Server 无法定位该条记录(这和第一次新增记录不同,新增不需要去定位记录位置),也就无法保存这1条记录,从而报错:无法找到应该有的1条中的0条。
[解决办法]
这样写更新代码很少看,不知道楼主这样的代码从哪里来?为何不写一个update语句直接提交更新数据呢?
sql="update tb set name='TEST2' where name='TEST'"
你那样写你不好检查,别人也不好检查
[解决办法]
新增,提交。然后再修改,在提交。
如果你刚刚新增的数据不保存到数据就要立刻修改,那么你为什么不直接新增这修改过的值呢?
[解决办法]
更新代码, 只有 DataTable 一条路吗?
感觉死死的, 一点都不灵活。
如果大批量的数据, 简单的数据修改, 用用还可以,
搞得复杂了, 还不如果换用其它的
[解决办法]
原因是:第一次新增时,本机内存中的datatable把新增记录各字段值update给 SQL Server, SQL Server 保存同时自动赋值id,但是该id并没有返回内存中的datatable,因此datatable中的这条记录是没有主键值的,此时如果程序又要修改该条记录,并想再次提交保存,此时 SQL Server 接到该记录的修改信息,但里面没有主键值, SQL Server 无法定位该条记录(这和第一次新增记录不同,新增不需要去定位记录位置),也就无法保存这1条记录,从而报错:无法找到应该有的1条中的0条。
private static void MergeIdentityColumns(string connectionString)
{
using (SqlConnection connection =
new SqlConnection(connectionString))
{
// Create the DataAdapter
SqlDataAdapter adapter =
new SqlDataAdapter(
"SELECT ShipperID, CompanyName FROM dbo.Shippers",
connection);
//Add the InsertCommand to retrieve new identity value.
adapter.InsertCommand = new SqlCommand(
"INSERT INTO dbo.Shippers (CompanyName) " +
"VALUES (@CompanyName); " +
"SELECT ShipperID, CompanyName FROM dbo.Shippers " +
"WHERE ShipperID = SCOPE_IDENTITY();", connection);
// Add the parameter for the inserted value.
adapter.InsertCommand.Parameters.Add(
new SqlParameter("@CompanyName", SqlDbType.NVarChar, 40,
"CompanyName"));
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.Both;
// MissingSchemaAction adds any missing schema to
// the DataTable, including identity columns
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
// Fill the DataTable.
DataTable shipper = new DataTable();
adapter.Fill(shipper);
// Add a new shipper.
DataRow newRow = shipper.NewRow();
newRow["CompanyName"] = "New Shipper";
shipper.Rows.Add(newRow);
// Add changed rows to a new DataTable. This
// DataTable will be used by the DataAdapter.
DataTable dataChanges = shipper.GetChanges();
// Add the event handler.
adapter.RowUpdated +=
new SqlRowUpdatedEventHandler(OnRowUpdated);
adapter.Update(dataChanges);
connection.Close();
// Merge the updates.
shipper.Merge(dataChanges);
// Commit the changes.
shipper.AcceptChanges();
Console.WriteLine("Rows after merge.");
foreach (DataRow row in shipper.Rows)
{
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
}
}
}