Search code examples
sql-serverentity-frameworkentity-framework-corerecursive-queryentity-framework-extensions

Entity Framework Extensions Recursive Query


There is a hierarchical query support in a popular EF extensions library: https://entityframework-extensions.net/to-self-hierarchy-list.

I'm curious how does it work under the hood? Is it getting handled by SQL server, meaning that the query is translated to CTE (common table expression)?


Solution

  • Disclaimer: I'm the owner of Entity Framework Extensions

    You got it right, we indeed use a CTE in the generated SQL.

    Here is how looks the SQL template:

    WITH
        SelfHierarchyQueryOuter AS (@(sqlMaster)),
        SelfHierarchyQueryInner AS (@(sqlHierarchy)),
        SelfHierarchyQuery AS (SELECT A.*, 0 AS ZZZ_Recursion FROM (SELECT * FROM SelfHierarchyQueryOuter) AS A 
                                        UNION ALL
                                        SELECT B.*, ZZZ_Recursion + 1 AS ZZZ_Recursion FROM  (SELECT * FROM SelfHierarchyQueryInner) AS B
                                        INNER JOIN SelfHierarchyQuery AS C ON @(keyJoins) 
                                        WHERE ZZZ_Recursion < @(maxRecursion)
                                        )
    
    @(selectFinal)
    FROM    SelfHierarchyQuery
    

    So a query like this one:

    var list2 = context.EntitySimples.ToSelfHierarchyList(x => x.Parent, options => options.MaxRecursion = 5);
    

    Will generate the following SQL:

    
    WITH
        SelfHierarchyQueryOuter AS (SELECT TOP 100 PERCENT  
        [Extent1].[ID] AS [ID], 
        [Extent1].[ColumnInt1] AS [ColumnInt1], 
        [Extent1].[ColumnInt2] AS [ColumnInt2], 
        [Extent1].[Parent_ID] AS [Parent_ID]
        FROM [dbo].[EntitySimple] AS [Extent1]),
        SelfHierarchyQueryInner AS (SELECT TOP 100 PERCENT  
        [Extent1].[ID] AS [ID], 
        [Extent1].[ColumnInt1] AS [ColumnInt1], 
        [Extent1].[ColumnInt2] AS [ColumnInt2], 
        [Extent1].[Parent_ID] AS [Parent_ID]
        FROM [dbo].[EntitySimple] AS [Extent1]),
        SelfHierarchyQuery AS (SELECT A.*, 0 AS ZZZ_Recursion FROM (SELECT * FROM SelfHierarchyQueryOuter) AS A 
                                        UNION ALL
                                        SELECT B.*, ZZZ_Recursion + 1 AS ZZZ_Recursion FROM  (SELECT * FROM SelfHierarchyQueryInner) AS B
                                        INNER JOIN SelfHierarchyQuery AS C ON C.[Parent_ID] = B.[ID] 
                                        WHERE ZZZ_Recursion < 5
                                        )
    
    SELECT *
    FROM    SelfHierarchyQuery
    
    

    Nothing "special" here, just using one great feature of the CTE to make it works.