查询多个级联路径的系统表

时间:2016-10-06 13:34:11

标签: sql-server entity-framework

我使用Entity Framework从我的模型中生成我的表,并且我不时地遇到多个级联路径的问题。 e.g:

  

引入FOREIGN KEY约束   ' FK_dbo.SurveyorSurveys_dbo.Surveys_Survey_ID'桌子上   ' SurveyorSurveys'可能导致循环或多个级联路径。

我发现在这个新表的级联路径所在的位置非常耗时,因此我可以删除其中一个级联删除。我认为如果我可以在系统表上运行查询,向我展示所涉及的完整路径,那将非常有用。有没有人知道如何做到这一点?

例如我有这个sql:

SELECT
    ro.name referenced_object,
    po.name parent_object,
    fk.name foreign_key
FROM sys.foreign_keys fk
    INNER JOIN sys.all_objects po
    ON fk.parent_object_id = po.object_id
    INNER JOIN sys.all_objects ro
    ON fk.referenced_object_id = ro.object_id
WHERE delete_referential_action_desc = 'CASCADE'
and (po.name = 'Surveys' or po.name = 'Surveyors'')
ORDER BY ro.name

但是这只会让我在层次结构中达到一个级别,在更高级别删除级联删除可能会更好,所以我最终调整并重新运行sql,直到我找到完整路径

2 个答案:

答案 0 :(得分:3)

这通常与recursive query有关。

首先澄清一下sys.all_objects中的列名:

  • parent_object_id是指拥有外键的对象,因此它不是关系中的父级,而是孩子。
  • referenced_object_id是关系中的父母。

知道了这一点,我们可以编写一个递归查询,通过将前一级别的子级与后续级别中的父级连接来收集外键关系树:

WITH [Cascades] AS(
    SELECT
        fk.referenced_object_id AS [RootId],
        fk.parent_object_id AS [ChildId],
        fk.referenced_object_id AS [ParentId],
        fk.name foreign_key,
        1 AS [Level]
    FROM sys.foreign_keys fk
    WHERE delete_referential_action_desc = 'CASCADE'

    UNION ALL

    SELECT [Cascades].[RootId],
        fk.parent_object_id,
        fk.referenced_object_id,
        fk.name foreign_key,
        [Cascades].[Level] + 1
    FROM sys.foreign_keys fk
    INNER JOIN [Cascades] ON [Cascades].[ChildId] = fk.referenced_object_id
    WHERE delete_referential_action_desc = 'CASCADE'
)
SELECT [root].Name AS [Root],
       po.Name AS [Parent],
       co.Name AS [Child],
       foreign_key,
       cs.[Level]
FROM [Cascades] cs
INNER JOIN sys.all_objects [root] ON cs.[RootId] = [root].object_id
INNER JOIN sys.all_objects po ON cs.ParentId = po.object_id
INNER JOIN sys.all_objects co ON cs.ChildId = co.object_id
WHERE [root].name = 'Surveys'
ORDER BY [Root], [Parent], [Level], [Child]

如果我在简单的树级层次结构中执行查询,则输出为:

Root Parent Child foreign_key Level
-----------------------------------
A    A      B1    FK_B1_A     1
A    A      B2    FK_B2_A     1
A    B1     C     FK_C_B1     2

答案 1 :(得分:2)

替代sql基于Gert的优秀答案。这个允许我指定叶子并显示每行的完整级联路径

WITH Cascades
AS (SELECT
    fk.parent_object_id,
    fk.referenced_object_id,
    fk.name foreign_keys,
    CAST(ro.name + ' -> ' + po.name AS nvarchar(256)) path,
    1 AS level
FROM sys.foreign_keys fk
    INNER JOIN sys.all_objects po
    ON fk.parent_object_id = po.object_id
    INNER JOIN sys.all_objects ro
    ON fk.referenced_object_id = ro.object_id
WHERE delete_referential_action_desc = 'CASCADE'
-- specifying leaf instead of root:
AND po.name IN ('Surveys', 'Surveyors', 'surveyorsurveys') 
UNION ALL SELECT
    fk.parent_object_id,
    fk.referenced_object_id,
    CAST(fk.name + ' -> ' + Cascades.foreign_keys as nvarchar(128)),
    CAST(ro.name + ' -> ' + cascades.path AS nvarchar(256)),
    cascades.level + 1
FROM sys.foreign_keys fk
    INNER JOIN sys.all_objects po
    ON fk.parent_object_id = po.object_id
    INNER JOIN sys.all_objects ro
    ON fk.referenced_object_id = ro.object_id
    INNER JOIN cascades
    ON cascades.referenced_object_id = fk.parent_object_id
WHERE delete_referential_action_desc = 'CASCADE')
SELECT
    path,
    foreign_keys,
    level
FROM Cascades
ORDER BY path