问题
I found this bug while working with a DataTable.
I added a primary key column to a DataTable, than added one row to that table, removed that row, and added row with the same key to the table. This works. When I tried to call RejectChanges() on it, I got ConstraintException saying that value is already present.
Here is the example:
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
I think since the row is deleted, exception should not be thrown (constraint is not violated because row is in deleted state). Is there something I can do about this? Any help is appreciated.
回答1:
I assume that this has the same cause than following bug issue since the first that will be rejected is your delete action:
DataTable.RejectChanges() should rollback rows in reverse order
Two possible workarounds:
Cycles through the DataRows rolling them back in reverse order. So the new records are removed before the previous ones are brought back to life.
DataRowCollection rows = dataTable.Rows;
for (int i = rows.Count - 1; i >= 0; i--)
{
rows[i].RejectChanges();
}
Disables constrains so the rollback can be done. Reenables constrains after that.
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 }Here's the way you "disable" constraints on a
DataTabletemporarily: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); }
回答2:
You can avoid this by using unique property of column tor true.
i.e. column.Unique = true;
As soon as this property is changed to true, a unique constraint will be created on this column to make sure that values are unique.
来源:https://stackoverflow.com/questions/9768066/datatable-throwing-exception-on-rejectchanges