两棵树和它们之间的联合表

时间:2016-01-24 20:55:16

标签: sql-server entity-framework linq tsql entity-framework-6

我有三个表:两个分层表和这些表之间的一个联结。

Teams
id  idParent
1   null
2   1
3   null
4   null
5   4

Projects
id  idParent
1   null
2   null
3   2
4   2
5   null

TeamProjects
idTeam  idProject
2       2
3       1
5       5

项目总是依赖于至少一个团队,这就是teamprojects的用途。

我试图实现的结果:对于每个对象(团队和项目),我想知道什么是上升和后代对象(id连接)

idObject    ascendantTeams  descendantTeam  ascendantProjects   descendantProjects
1                                   2                               7, 10
2            1                                                      7
3                                                                   6
4               
5            4                                                      10
6            3          
7            2                                                      8, 9
8            2                                  7   
9            2                                  7   
10           5          

我正在尝试使用linq to entity查询来实现这一点,但是我需要CTE(用于递归部分)和(stuff-for-xml)用于连接部分......并且都不能将linq转换为实体。 所以我试图提供帮助,但我也没有设法为它编写sql。

如何使用linq to entities或sql?

解决这个问题

1 个答案:

答案 0 :(得分:1)

你所拥有的不是很清楚。

所以,我做了一些假设,以便提出解决方案。我假设一个项目将包含在descendantProjects中,用于基于团队的结果(参见dbo.GetProjectsForTeam),一个团队将被包含在descendantTeams中,用于基于项目的结果(参见dbo.GetTeamsForProject)。从你的问题来看,这一点都不清楚。

您需要创建标量值函数来实现您的场景。

如何调用标量值函数

这些函数中的每一个都有两个参数 - 一个类型参数,对于后代来说是a,对于后代来说是d,而对于基于团队的查询,它将是团队ID的id基于项目的查询的项目ID

团队相关标量值函数

CREATE FUNCTION [dbo].[GetTeamsForTeam](
               @teamType VARCHAR(20) , --either 'a' for ascendants or 'd' for descendants
               @teamId   INT)
RETURNS VARCHAR(MAX)
AS
     BEGIN
         DECLARE @list VARCHAR(MAX);
         IF @teamType = 'a'
             BEGIN
                 --get all parent teams
                 SELECT @list = COALESCE(@list+','+CAST(t.Id AS VARCHAR(10)) , CAST(t.Id AS VARCHAR(10)))
                 FROM dbo.Teams AS t
                 WHERE t.Id IN ( SELECT t2.IdParent
                                 FROM dbo.Teams AS t2
                                 WHERE t2.id = @teamId
                               );
             END;
         ELSE
             BEGIN
                 --get all children teams including @teamId
                 SELECT @list = COALESCE(@list+','+CAST(t.Id AS VARCHAR(10)) , CAST(t.Id AS VARCHAR(10)))
                 FROM dbo.Teams AS t
                 WHERE t.Id IN ( SELECT t2.Id
                                 FROM dbo.Teams AS t2
                                 WHERE t2.IdParent = @teamId
                                       OR
                                       t2.Id = @teamId
                               );
             END;
         RETURN @list;
     END;
GO


CREATE FUNCTION [dbo].[GetProjectsForTeam](
               @projectType VARCHAR(1) , --either 'a' for ascendants or 'd' for descendants
               @teamId       INT)
RETURNS VARCHAR(MAX)
AS
     BEGIN
         DECLARE @projects VARCHAR(MAX);
         IF @projectType = 'a'
             BEGIN
                 --get projects for all the parents of @teamId
                 SELECT @projects = COALESCE(@projects+','+CAST(tp.idProject AS VARCHAR(10)) , CAST(tp.idProject AS VARCHAR(10)))
                 FROM dbo.TeamProjects AS tp
                 WHERE tp.idTeam IN ( SELECT t.IdParent
                                      FROM dbo.Teams AS t
                                      WHERE t.Id = @teamId
                                    );
             END;
         ELSE
             BEGIN
                 --get projects for all children of @teamId including @teamId
                 SELECT @projects = COALESCE(@projects+','+CAST(tp.idProject AS VARCHAR(10)) , CAST(tp.idProject AS VARCHAR(10)))
                 FROM dbo.TeamProjects AS tp
                 WHERE tp.idTeam IN ( SELECT t.Id
                                      FROM dbo.Teams AS t
                                      WHERE t.IdParent = @teamId OR t.Id = @teamId
                                    );
             END;
         RETURN @projects;
     END;
GO

使用上述标量值函数,基于团队的查询来实现最终结果集如下所示。

SELECT t.id AS TeamId,
       dbo.GetTeamsForTeam('a', t.id) AS ascendantTeams,
       dbo.GetTeamsForTeam('d', t.id) AS descendantTeams,
       dbo.GetProjectsForTeam('a', t.id) AS ascendantProjects,
       dbo.GetProjectsForTeam('d', t.id) AS descendantProjects
FROM Teams t;

与项目相关的标量值函数

CREATE FUNCTION [dbo].[GetTeamsForProject] (
                @teamType  VARCHAR(20) , --either 'a' for ascendants or 'd' for descendants
                @projectId INT
                                           )
RETURNS VARCHAR(MAX)
AS
     BEGIN
         DECLARE @list VARCHAR(MAX);
         IF @teamType = 'a'
             BEGIN
                 --get all parent teams
                 SELECT @list = COALESCE(@list+','+CAST(t.Id AS VARCHAR(10)) , CAST(t.Id AS VARCHAR(10)))
                 FROM dbo.Teams AS t
                 WHERE t.Id IN ( SELECT t2.IdParent
                                 FROM dbo.Projects AS p INNER JOIN dbo.TeamProjects AS tp ON p.Id = tp.idProject
                                                        INNER JOIN dbo.Teams AS t2 ON t2.id = tp.idTeam
                                 WHERE p.id = @projectId
                               );
             END;
         ELSE
             BEGIN
                 --get all children teams including team for @projectId
                 SELECT @list = COALESCE(@list+','+CAST(t.Id AS VARCHAR(10)) , CAST(t.Id AS VARCHAR(10)))
                 FROM dbo.Teams AS t
                 WHERE t.Id IN ( SELECT t2.Id
                                 FROM dbo.Projects AS p INNER JOIN dbo.TeamProjects AS tp ON p.Id = tp.idProject
                                                        INNER JOIN dbo.Teams AS t2 ON t2.id = tp.idTeam
                                 WHERE p.IdParent = @projectId OR p.Id = @projectId 
                               );
             END;
         RETURN @list;
     END;

GO


CREATE FUNCTION [dbo].[GetProjectsForProject] (
                @projectType VARCHAR(1) , --either 'a' for ascendants or 'd' for descendants
                @projectId   INT
                                              )
RETURNS VARCHAR(MAX)
AS
     BEGIN
         DECLARE @projects VARCHAR(MAX);
         IF @projectType = 'a'
             BEGIN
                 --get projects for all the parents of @projectId
                 SELECT @projects = COALESCE(@projects+','+CAST(p.idParent AS VARCHAR(10)) , CAST(p.idParent AS VARCHAR(10)))
                 FROM dbo.Projects AS p
                 WHERE p.Id IN ( SELECT p.IdParent
                                 FROM dbo.Projects AS p
                                 WHERE p.Id = @projectId
                               );
             END;
         ELSE
             BEGIN
                 --get projects for all children of @projectd
                 SELECT @projects = COALESCE(@projects+','+CAST(p.id AS VARCHAR(10)) , CAST(p.id AS VARCHAR(10)))
                 FROM dbo.Projects AS p
                 WHERE p.IdParent IN ( SELECT p.Id
                                       FROM dbo.Projects AS p
                                       WHERE p.IdParent = @projectId OR p.Id = @projectId     
                                     );
             END;
         RETURN @projects;
     END;

GO

使用上述基于项目的函数,基于项目的查询的查询如下所示。

SELECT p.id AS ProjectId,
       dbo.GetTeamsForProject('a', p.id) AS ascendantTeams,
       dbo.GetTeamsForProject('d', p.id) AS descendantTeams,
       dbo.GetProjectsForProject('a', p.id) AS ascendantProjects,
       dbo.GetProjectsForProject('a', p.id) AS descendantProjects
FROM dbo.Projects p;

我使用的样本数据和最终查询的屏幕截图如下所示。

Screen shot of Sample Data with Results