我在使用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
我认为由于删除了行,因此不应抛出异常(因为行处于删除状态,所以不会违反约束)。我可以做些什么吗?任何帮助表示赞赏。
答案 0 :(得分:3)
我认为这与导致错误问题的原因相同,因为第一个将被拒绝的是您的delete
操作:
DataTable.RejectChanges() should rollback rows in reverse order
两种可能的解决方法:
循环通过DataRows以相反的顺序回滚它们。所以 新记录在之前的记录被删除之前被删除 寿命。
DataRowCollection rows = dataTable.Rows;
for (int i = rows.Count - 1; i >= 0; i--)
{
rows[i].RejectChanges();
}
禁用约束,以便可以完成回滚。在此之后,重新启用会受到限制。
您可以使用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
}
以下是您"禁用"的方式对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);
}
答案 1 :(得分:0)
您可以使用列unique
列的true
属性来避免这种情况。
即。 column.Unique = true;
只要此属性更改为true,就会在此列上创建唯一约束,以确保值是唯一的。