【问题标题】:How do I make updates to data in a unique-constrained column across multiple rows without risking violating the constraint?如何在不违反约束的情况下跨多行更新唯一约束列中的数据?
【发布时间】:2017-08-24 20:53:05
【问题描述】:
我有一个表,其中有一列具有唯一约束。用户将以绑定到 DataGrid 的 DataTable 的形式编辑此表中的数据。一旦他们完成修改数据,保存功能必须将他们的更改应用回数据库。出于应用程序架构的原因,对数据库的每次更改都必须作为创建、更新或删除操作一次执行一行。我可以验证 DataTable 以确保最终结果不会违反约束,但似乎不可能验证它在两者之间永远不会被违反。即使我不允许 DataGrid 本身内部存在重复值,用户也可以在进行违反约束的修改时放入一个占位符值,并且 DataTable 类似乎只存储每行的原始版本和最终版本,而不是中间版本。
在对数据进行这些更改时,如何避免任何唯一约束违规?
【问题讨论】:
标签:
sql
.net
sql-server
wpf
vb.net
【解决方案1】:
最简单的方法是更新 SQL 语句中的所有约束值:
UPDATE [Foo] Set [SomeUniqueValue] = CASE [ID] WHEN 1 THEN 'A' WHEN 2 THEN 'B' WHEN 3 THEN 'C' END WHERE [ID] IN (1,2,3)
如果您交换值,这不会违反唯一性,只要在语句完成时保持唯一性即可。
如果您必须一次执行一行,您可能不得不强行遍历更新列表,在失败时捕获错误,并在循环中不断重试出错的那些,直到所有更新完成,或者无法进行更多更新:
bool didSomething;
List<Row> rowsThatNeedToTryAgain = new List<Row>();
do {
didSomething = false;
rowsThatNeedToTryAgain.Clear();
foreach (Row row in rowsToUpdate) {
try {
UpdateTheRowInTheDatabase(row);
didSomething = true;
} catch {
rowsThatNeedToTryAgain.Add(row);
}
}
rowsToUpdate.Clear();
rowsToUpdate.AddRange(rowsThatNeedToTryAgain);
} while (didSomething && rowsThatNeedToTryAgain.Count > 0);
if (rowsThatNeedToTryAgain.Count > 0)
throw new Exception("sorry, couldn't do 'em all");
更优雅的解决方案可能会在不访问数据库的情况下从代码中执行此操作,但这会假设您的进程是当时唯一的更新。