我可以从 InvalidConstraintException 中检索受影响的约束吗?

Can I retrieve the impacted constraint(s) from a InvalidConstraintException?

两天前,。那个问题已经回答了,但是现在我想概括一下我的程序:

目前我有:

try
{ 
dt_MainTable1.Rows[0].Delete();
}
catch (Exception ex)
{
    if (MessageBox.Show("In order to avoid data corruption, not only " + 
                          " the required tupple will be deleted, " + 
                          "but also the ones in other tables, " + 
                          "referring to that tupple. " + 
                          "Is that what you want?",
                        "Warning",
                        MessageBoxButton.YesNo) == MessageBoxResult.Yes)
    {
        (ForeignKeyConstraint)(dt_SubTable1.Constraints[0]).DeleteRule 
          = Rule.Cascade;
        dt_MainTable1.Rows[0].Delete();
        (ForeignKeyConstraint)(dt_SubTable1.Constraints[0]).DeleteRule
          = Rule.None;
    }
}

... 这就是我想要的:我尝试做一些事情(比如修改或删除),但我陷入 System.Data.InvalidConstraintException,基于 Constraint.然后我提出一个问题,并根据答案将受影响的 ConstraintDeletion RuleModification Rule 转换为 NoneCascade。大问题:我可以从生成的 System.Data.InvalidConstraintException 中检索受影响的 Constraint 吗? (我一直在调试和检查System.Data.InvalidConstraintException的属性,但我没有找到任何东西),只是为了展示我想要的(见ex.FindRelevantConstraints()方法):

try
{ 
LaunchDeleteAction(...);
}
catch (Exception ex)
{
    if (MessageBox.Show("In order to avoid data corruption, not only " + 
                          " the required tupple will be deleted, " + 
                          "but also the ones in other tables, " + 
                          "referring to that tupple. " + 
                          "Is that what you want?",
                        "Warning",
                        MessageBoxButton.YesNo) == MessageBoxResult.Yes)
    {
        for each (ForeignKeyConstraint C in ex.FindRelevantConstraints()   <===
          C.DeleteRule = Rule.Cascade;
        LaunchDeleteAction(...);
        for each (ForeignKeyConstraint C in ex.FindRelevantConstraints()   <===
          C.DeleteRule = Rule.None;
    }
}

进一步调查后编辑

与此同时,我发现 Exceptionex 包含相应 Constraint 的名称,您可以在下面的手表 window 摘录中看到:

ex.Message : Cannot delete this row because constraints are enforced on relation Constraint1, and deleting this row will strand child rows.

我的意思是,解析 Exception 的消息不可能是为了获得对我正在寻找的 Constraint 对象的引用?

绝望编辑
与此同时,我决定为我正在创建的 Constraint 对象指定特殊的名称,就像您在此处看到的那样:

dt_SubTable1.Constraints.Add(
  new ForeignKeyConstraint("|FKC|MainTable.SubId|SubTable.Id|", 
                           dt_SubTable.Columns["Id"],
                           dt_MainTable.Columns["SubId"])
    { DeleteRule = Rule.None, 
      UpdateRule = Rule.None });

如您所见,我可以使用管道字符分隔 table 名称,使用点来查找列名称,但这确实是一个绝望的想法:-)

作为一般规则,最好测试是否存在会导致异常的事物,而不是捕获它。

同样在 catch 块中处理用户交互并不理想,更改数据完整性约束以执行操作似乎是错误的处理方式。

更好的方法可能是:

  • 测试其他 tables
  • 中是否存在任何相关数据
  • 如果找到:向用户显示消息
  • 如果用户点击继续:先删除相关数据,最后删除父记录

如果关系像示例中的主要和子 table 一样简单,您可以尝试类似

if (dt_SubTable1.AsEnumerable.Any(r => s => r.Field("ForeignIdField") == MainId))

如果您有几个 DataTable 个实例,您可以遍历它们检查代码中的 Constraints 属性。

foreach (var constraint in dt_Sub1.Contstraints)
{
    if (constraint is ForeignKeyConstraint && constraint.RelatedTable.TableName = dt_Main.TableName)
    // check for matching data
}

如果您正在尝试更通用的方法 This question 有几种方法展示了如何找到给定 table 的外键。您可以创建一个方法 FindRelevantConstraints(string tableName) 包装系统存储过程 sp_fkeys,它将 return table 名称和字段名称。

这将允许您使用 id 值

为依赖于您的主要 table 的任何和所有子 table 创建查询

直接回答标题中的问题:

Can I retrieve the impacted constraint(s) from a InvalidConstraintException?

不,很遗憾,你不能。

根据参考来源,InvalidConstraintException 除了消息文本和(如果适用)内部异常之外不存储任何有用的信息。

一些额外的阅读表明 the System.Data methods pass all relevant information (e.g. the constraint name) to the ExceptionBuilder methods,但是,唉,这个信息只用于创建异常消息然后被丢弃。