DataTable 在 RejectChanges 上抛出异常

Val*_*ale 5 c# datatable .net-4.0

我在使用 DataTable 时发现了这个错误。我向 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
Run Code Online (Sandbox Code Playgroud)

我认为由于行已被删除,因此不应抛出异常(由于行处于已删除状态,因此不会违反约束)。我能做些什么吗?任何帮助表示赞赏。

Tim*_*ter 4

我认为这与以下错误问题具有相同的原因,因为第一个被拒绝的是您的delete操作:

DataTable.RejectChanges() 应该以相反的顺序回滚行

两种可能的解决方法:

循环遍历 DataRows,以相反的顺序回滚它们。因此,在以前的记录恢复之前,新记录就会被删除。

DataRowCollection rows = dataTable.Rows;
for (int i = rows.Count - 1; i >= 0; i--)
{
    rows[i].RejectChanges();
}
Run Code Online (Sandbox Code Playgroud)

禁用约束以便可以完成回滚。之后重新启用约束。

  1. 您可以使用 LINQ-to-DataSet 来定义您自己的“回滚顺序”:

    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
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 以下是暂时“禁用”约束的方法DataTable

    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);
    }
    
    Run Code Online (Sandbox Code Playgroud)