我希望能够检查从SQL Server 2008中的表中删除行是否会因外键违规而失败而不尝试删除它。
基本上,如果用户无法删除它,我不想向用户显示删除按钮,因为该密钥已在其他地方使用。
我在应用程序的许多地方需要这个,所以不要真的想手动编写检查以查看删除行是否安全。有关实现这一目标的最佳方法的任何建议吗?
我正在使用实体框架来访问数据。
答案 0 :(得分:2)
没有快速简便的方法来检查这一点。你可以使用information_schema
构建一些动态的东西,但毫无疑问它会很丑陋而且不是很快。
绝对最佳选择是每个位置验证几行自定义代码。
另一个选择是启动一个事务,尝试删除。如果它失败了,那么你知道。如果成功,则回滚事务,并且您知道可以删除。这仍然是丑陋的,并且以一种有点破碎的方式使用交易,但它会起作用。但是,请确保表中没有启用级联删除。
答案 1 :(得分:2)
查询时,对子表执行LEFT JOIN。使用CanDelete计算值来决定是否应显示该按钮。如果每个父行超过1个子行,则此处的COUNT将删除重复项。
SELECT
Col1, Col2, Col3, ...,
CASE C.Existence WHEN 0 THEN 1 ELSE 0 END AS CanDelete
FROM
ParentTable P
LEFT JOIN
(
SELECT COUNT(*) AS Existence, FKColumn
FROM Childtable GROUP BY FKColumn
) C ON P.FKColumn = C.FKColumn
WHERE
P.Col = ...
另一种方式可能是
SIGN(C.Existence) AS HasChildRows
答案 2 :(得分:1)
我在以前的应用程序中做过这种事情。我创建了一个名为TryDelete()的函数。在方法内部,我试图删除所需的行。如果我得到了FK异常,我抓住它并返回false。在任何一种情况下,无论是真还是假,我都会在事务中封装删除,然后将其回滚。
答案 3 :(得分:1)
您可以在实体的部分类中添加一个方法,该方法将检查引用的对象是否存在。
例如,假设您有Entity1,其中包含Entity2的集合。基本上,在每个实体部分类中,您将编写一个属性IsReferenced
,其中包含:
正如您猜测的那样,您需要确保在提取中始终包含引用的值,或者,如果您在上下文中工作,则可以在{{1}中使用.Load()
在检查之前获取实体。这是一个开销,它取决于你是否愿意“支付”它。
然后,您可以根据需要显示/隐藏“删除”按钮,从而避免每次都重复检查。
答案 4 :(得分:0)
我认为你有两种可能的选择。既然你不能保证所有的关系都会映射到你的OM中,你就必须在数据库上检查它。
您可以在之后回滚的事务中尝试实际删除,但如果您必须使用级联删除配置禁令,这也可以使用...
另一种方法是从sysobjects表中提取所有约束,并验证每个表没有记录。但这需要一些动态SQL,这也可能会变得非常混乱。
答案 5 :(得分:0)
如果您在数据库级别,我会加入可能存在冲突的所有表。
任何返回的记录都无法删除,这意味着剩余的设置可以是。
答案 6 :(得分:0)
假设数据库由多个用户(绝大多数用户)使用 - 在“检查”删除是否可行以及用户可能决定删除行之间会有一个机会窗口,在此期间有人否则可能会执行一些否定测试结果的活动。
这意味着您可能会显示“删除”按钮,但是当您尝试删除时,它就不再可能。此外,您可能不会显示“删除”按钮,但是当用户决定要删除该行(但找不到该按钮)时,应该允许他们这样做。
没有办法避免这种比赛。如果他们愿意,我只是让人们尝试删除,但要准备好处理外键导致的失败。