DataTable在RejectChanges时抛出异常

5

我在使用DataTable时发现了一个bug。 我向DataTable添加了一个主键列,然后向该表添加了一行数据,删除了该行数据,再次添加具有相同主键的行数据。这个操作是有效的。但是当我尝试调用RejectChanges()时,却出现了ConstraintException,提示该值已经存在。 以下是示例:

    var dataTable = new DataTable();
    var column = new DataColumn("ID", typeof(decimal));
    dataTable.Columns.Add(column);
    dataTable.PrimaryKey =  new [] {column };

    decimal id = 1;

    var oldRow = dataTable.NewRow();
    oldRow[column] = id;

    dataTable.Rows.Add(oldRow);
    dataTable.AcceptChanges();

    oldRow.Delete();

    var newRow = dataTable.NewRow();
    newRow[column] = id;

    dataTable.Rows.Add(newRow);
    dataTable.RejectChanges(); // This is where it crashes

我认为既然行已被删除,就不应该引发异常(因为行处于已删除状态,不违反约束)。我能做些什么来解决这个问题吗?非常感谢您的帮助。

2个回答

4
我假设这个问题与以下错误问题有相同的原因,因为首先被拒绝的是您的delete操作: DataTable.RejectChanges() 应该按相反顺序回滚行 两种可能的解决方法:
循环遍历数据行并以相反的顺序将它们回滚。这样,在将之前的记录恢复之前,新记录就被删除了。
DataRowCollection rows = dataTable.Rows;
for (int i = rows.Count - 1; i >= 0; i--)
{
    rows[i].RejectChanges();
}

禁用约束条件以便可以执行回滚操作。之后重新启用约束条件。

  1. You could use LINQ-to-DataSet to define your own "rollback-order":

    var rollbackPlan = (from r in dataTable.AsEnumerable()
                   where r.RowState != DataRowState.Unchanged
                   let firstOrder  = r.RowState==DataRowState.Deleted? 1 : 0
                   let secondOrder = r.RowState==DataRowState.Added?   1 : 0
                   orderby firstOrder ascending, secondOrder ascending
                   select r).ToList();
    foreach (DataRow r in rollbackPlan)
    {
        r.RejectChanges(); // Does not crash anymore
    }
    
  2. Here's the way you "disable" constraints on a DataTable temporarily:

    var constraintBackup = dataTable.Constraints.Cast<System.Data.Constraint>().ToList();
    dataTable.Constraints.Clear();
    dataTable.RejectChanges(); // Does not crash anymore
    foreach (System.Data.Constraint c in constraintBackup)
    {
        dataTable.Constraints.Add(c);
    }
    

1
这是类似的东西,但我认为它不应该按相反的顺序回滚。它应该先拒绝“未删除”行上的更改,然后再拒绝已删除的行上的更改。 - Vale
第二个解决方法可行(但如何禁用约束条件)。第一个不是通用解决方案,因为用户可以删除最后一行,然后更改前一行的ID。 - Vale
@Vale:我编辑了我的答案,展示了一种你可以强制正确回滚顺序的方法。 - Tim Schmelter
@Vale:展示了如何暂时“禁用”DataTable上的约束。 - Tim Schmelter
这是目前为止最好的解决方案。如果没有更好的建议,我很快就会接受你的答案。 - Vale

0

您可以通过将列的unique属性设置为true来避免这种情况。

例如:column.Unique = true;

一旦将此属性更改为true,就会在该列上创建一个唯一约束,以确保值是唯一的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接