C# 这是DataTableAPI中的错误吗?更改存储/执行在";“顺序错误”;
编辑:无论您是否认为这是一个.NET错误,任何评论都将不胜感激 我有一个bug,我设法将其简化为以下场景: 我有一个数据表,其中主键必须保持连续,例如,如果在其他行之间插入一行,则必须首先增加后续行的ID以留出空间,然后插入该行 如果删除一行,则必须减少任何后续行的ID,以填补表中该行留下的空白 正常工作的测试用例 从表中的3行开始,ID为1、2和3 然后删除ID=2,设置ID=2,其中ID=3(以填补空白);这是正确的。GetChanges()包含删除的行,然后是修改的行;当您运行dataAdapter.Update(表)时,它会正常执行 不起作用的测试用例 但是,如果从两行(ID1和ID2)开始,然后设置ID=3,其中ID=2,插入ID=2,然后提交(或接受)更改。现在,该状态应与第一次测试的状态相同 然后执行与前面相同的步骤,即删除ID=2并设置ID=2,其中ID=3,但现在dataTable.GetChanges()的顺序错误。第一行是修改的行,第二行是删除的行。然后,如果您尝试dataAdapter.Update(table),它将给出一个主键冲突-它试图在删除之前将一行修改为一个已经存在的行 解决方法 我可以想出解决这个问题的办法,即强制执行,以便先提交删除的行,然后提交修改的行,然后再添加行。但为什么会这样?还有别的解决办法吗 我想我以前在字典中也看到过类似的“问题”,如果你添加一些条目,然后删除,然后重新插入它们,那么它们将不会与你添加它们的顺序相同(当你枚举字典时) 这里有两个NUnit测试显示了问题:C# 这是DataTableAPI中的错误吗?更改存储/执行在";“顺序错误”;,c#,datatable,dataadapter,C#,Datatable,Dataadapter,编辑:无论您是否认为这是一个.NET错误,任何评论都将不胜感激 我有一个bug,我设法将其简化为以下场景: 我有一个数据表,其中主键必须保持连续,例如,如果在其他行之间插入一行,则必须首先增加后续行的ID以留出空间,然后插入该行 如果删除一行,则必须减少任何后续行的ID,以填补表中该行留下的空白 正常工作的测试用例 从表中的3行开始,ID为1、2和3 然后删除ID=2,设置ID=2,其中ID=3(以填补空白);这是正确的。GetChanges()包含删除的行,然后是修改的行;当您运行dataAd
[Test]
public void GetChanges_Working()
{
// Setup ID table with three rows, ID=1, ID=2, ID=3
DataTable idTable = new DataTable();
idTable.Columns.Add("ID", typeof(int));
idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };
idTable.Rows.Add(1);
idTable.Rows.Add(2);
idTable.Rows.Add(3);
idTable.AcceptChanges();
// Delete ID=2, and move old ID=3 to ID=2
idTable.Select("ID = 2")[0].Delete();
idTable.Select("ID = 3")[0]["ID"] = 2;
// Debug GetChanges
foreach (DataRow row in idTable.GetChanges().Rows)
{
if (row.RowState == DataRowState.Deleted)
Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
else
Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
}
// Check GetChanges
Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}
输出:
Deleted: 2
Modified: 3 = 2
1 passed, 0 failed, 0 skipped, took 4.27 seconds (NUnit 2.4).
Modified: 3 = 2
Deleted: 2
TestCase 'GetChanges_NotWorking'
failed:
1st row in GetChanges should be deleted row
Expected: Deleted
But was: Modified
下一个测试:
[Test]
public void GetChanges_NotWorking()
{
// Setup ID table with two rows, ID=1, ID=2
DataTable idTable = new DataTable();
idTable.Columns.Add("ID", typeof(int));
idTable.PrimaryKey = new DataColumn[] { idTable.Columns["ID"] };
idTable.Rows.Add(1);
idTable.Rows.Add(2);
idTable.AcceptChanges();
// Move old ID=2 to ID=3, and add ID=2
idTable.Select("ID = 2")[0]["ID"] = 3;
idTable.Rows.Add(2);
idTable.AcceptChanges();
// Delete ID=2, and move old ID=3 to ID=2
idTable.Select("ID = 2")[0].Delete();
idTable.Select("ID = 3")[0]["ID"] = 2;
// Debug GetChanges
foreach (DataRow row in idTable.GetChanges().Rows)
{
if (row.RowState == DataRowState.Deleted)
Console.WriteLine("Deleted: {0}", row["ID", DataRowVersion.Original]);
else
Console.WriteLine("Modified: {0} = {1}", row["ID", DataRowVersion.Original], row["ID", DataRowVersion.Current]);
}
// Check GetChanges
Assert.AreEqual(DataRowState.Deleted, idTable.GetChanges().Rows[0].RowState, "1st row in GetChanges should be deleted row");
Assert.AreEqual(DataRowState.Modified, idTable.GetChanges().Rows[1].RowState, "2nd row in GetChanges should be modified row");
}
输出:
Deleted: 2
Modified: 3 = 2
1 passed, 0 failed, 0 skipped, took 4.27 seconds (NUnit 2.4).
Modified: 3 = 2
Deleted: 2
TestCase 'GetChanges_NotWorking'
failed:
1st row in GetChanges should be deleted row
Expected: Deleted
But was: Modified
这不是一个bug,关键是你使用ID的方式(非常)不标准。两个答案: 1) 使用DataTable.GetChanges(DataRowState.Modified)按顺序处理更新(我认为它会被删除、修改和插入)。这也是主/细节关系(在.NET3.0之前)必须做的事情
2) 重新考虑一下您的设计,一般来说,ID应该是不可变的,并考虑到间隙等。这将使您的所有数据库操作更加可靠和容易。您可以使用另一列来维护向用户显示的顺序编号。+1表示“一般情况下,ID应该是不可变的”和“您可以使用另一列来维护向用户显示的顺序编号”。我明白您的观点,即不应以这种方式使用主键;但对我来说,DataTable的行为似乎仍然很奇怪——也就是说,如果我这样使用它,它应该可以工作。相关的,为什么DataAdapter.Update的默认行为不是以删除、修改然后插入的顺序进行处理。(顺便说一句,这是我本想输入解决方案的顺序-我现在已经在原文中更正了)。@Rick:适配器的功能“有限”(即无法处理关系),因此如果你想要非标准的东西,你必须自己处理。好的,谢谢,我会等待其他人的回答,否则我会接受你的回答。