检查删除行是否安全

时间:2010-11-23 14:04:20

标签: c# sql-server entity-framework sql-server-2008 asp.net-mvc-2

我希望能够检查从SQL Server 2008中的表中删除行是否会因外键违规而失败而不尝试删除它。

基本上,如果用户无法删除它,我不想向用户显示删除按钮,因为该密钥已在其他地方使用。

我在应用程序的许多地方需要这个,所以不要真的想手动编写检查以查看删除行是否安全。有关实现这一目标的最佳方法的任何建议吗?

我正在使用实体框架来访问数据。

7 个答案:

答案 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,其中包含:

  • 如果Entity1在Entity2中有任何项目
  • ,则Entity1返回true
  • 如果存在对Entity1的引用
  • ,则返回Entity2

正如您猜测的那样,您需要确保在提取中始终包含引用的值,或者,如果您在上下文中工作,则可以在{{1}中使用.Load()在检查之前获取实体。这是一个开销,它取决于你是否愿意“支付”它。

然后,您可以根据需要显示/隐藏“删除”按钮,从而避免每次都重复检查。

答案 4 :(得分:0)

我认为你有两种可能的选择。既然你不能保证所有的关系都会映射到你的OM中,你就必须在数据库上检查它。

您可以在之后回滚的事务中尝试实际删除,但如果您必须使用级联删除配置禁令,这也可以使用...

另一种方法是从sysobjects表中提取所有约束,并验证每个表没有记录。但这需要一些动态SQL,这也可能会变得非常混乱。

答案 5 :(得分:0)

如果您在数据库级别,我会加入可能存在冲突的所有表。

任何返回的记录都无法删除,这意味着剩余的设置可以是。

答案 6 :(得分:0)

假设数据库由多个用户(绝大多数用户)使用 - 在“检查”删除是否可行以及用户可能决定删除行之间会有一个机会窗口,在此期间有人否则可能会执行一些否定测试结果的活动。

这意味着您可能会显示“删除”按钮,但是当您尝试删除时,它就不再可能。此外,您可能不会显示“删除”按钮,但是当用户决定要删除该行(但找不到该按钮)时,应该允许他们这样做。

没有办法避免这种比赛。如果他们愿意,我只是让人们尝试删除,但要准备好处理外键导致的失败。