Entity Framework 扩展递归查询
Entity Framework Extensions Recursive Query
流行的 EF 扩展库中有分层查询支持:https://entityframework-extensions.net/to-self-hierarchy-list。
我很好奇它是如何工作的?它是否由 SQL 服务器处理,这意味着查询被转换为 CTE(常见的 table 表达式)?
免责声明:我是Entity Framework Extensions
的所有者
你没看错,我们确实在生成的 SQL 中使用了 CTE。
SQL 模板的外观如下:
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
所以这样的查询:
var list2 = context.EntitySimples.ToSelfHierarchyList(x => x.Parent, options => options.MaxRecursion = 5);
将生成以下 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
这里没有什么“特别”之处,只是使用了 CTE 的一项重要功能使其发挥作用。
流行的 EF 扩展库中有分层查询支持:https://entityframework-extensions.net/to-self-hierarchy-list。
我很好奇它是如何工作的?它是否由 SQL 服务器处理,这意味着查询被转换为 CTE(常见的 table 表达式)?
免责声明:我是Entity Framework Extensions
的所有者你没看错,我们确实在生成的 SQL 中使用了 CTE。
SQL 模板的外观如下:
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
所以这样的查询:
var list2 = context.EntitySimples.ToSelfHierarchyList(x => x.Parent, options => options.MaxRecursion = 5);
将生成以下 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
这里没有什么“特别”之处,只是使用了 CTE 的一项重要功能使其发挥作用。