LINQ中有多个左连接

时间:2014-08-14 18:52:14

标签: c# sql linq join

我正在尝试将SQL查询转换为LINQ,并且无法正确获取语法。我的原始(工作)SQL查询是:

 SELECT a.PersonnelNumber,
    a.LastName,
    a.FirstName,
    a.MiddleInitial,
    b.Title,
    b.Division,
    b.Section,
    b.Unit,
    d.PersonnelNumber AS SupervisorPersonnelNumber
FROM Person a
     JOIN Position b ON a.PositionID = b.PositionID
     LEFT JOIN Position c ON b.SupervisorPositionID = c.PositionID
     LEFT JOIN Person d ON c.PositionID = d.PositionID

我将其转换为以下LINQ:

var query = from a in ctx.People
            from b in ctx.Positions.Where(b => a.PositionID == b.PositionID)
            from c in ctx.Positions.Where(c => b.SupervisorPositionID == c.PositionID).DefaultIfEmpty()
            from d in ctx.People.Where(d => c.PositionID == d.PositionID).DefaultIfEmpty()
            select new { 
                            a.PersonnelNumber, 
                            a.LastName, 
                            a.FirstName, 
                            a.MiddleInitial, 
                            b.Title, 
                            b.Division, 
                            b.Section, 
                            b.Unit, 
                            SupervisorPersonnelNumber = d.PersonnelNumber
                       };

这种返回的方式比我预期的结果更多(20000+而不是~1100)所以我查看了生成的SQL:

SELECT 
[Extent2].[PositionID] AS [PositionID], 
[Extent1].[PersonnelNumber] AS [PersonnelNumber], 
[Extent1].[LastName] AS [LastName], 
[Extent1].[FirstName] AS [FirstName], 
[Extent1].[MiddleInitial] AS [MiddleInitial], 
[Extent2].[Title] AS [Title], 
[Extent2].[Division] AS [Division], 
[Extent2].[Section] AS [Section], 
[Extent2].[Unit] AS [Unit], 
[Extent4].[PersonnelNumber] AS [PersonnelNumber1]
FROM    [dbo].[Person] AS [Extent1]
INNER JOIN [dbo].[Position] AS [Extent2] ON [Extent1].[PositionID] = [Extent2].[PositionID]
LEFT OUTER JOIN [dbo].[Position] AS [Extent3] ON [Extent2].[SupervisorPositionID] = [Extent3].[PositionID]
LEFT OUTER JOIN [dbo].[Person] AS [Extent4] ON ([Extent3].[PositionID] = [Extent4].[PositionID]) OR (([Extent3].[PositionID] IS NULL) AND ([Extent4].[PositionID] IS NULL))

最后一行是导致我的问题的原因:

LEFT OUTER JOIN [dbo].[Person] AS [Extent4] ON ([Extent3].[PositionID] = [Extent4].[PositionID]) OR (([Extent3].[PositionID] IS NULL) AND ([Extent4].[PositionID] IS NULL))

我不确定为什么添加了额外的OR子句并删除它会返回所需的结果。

如果它有帮助,Position表格(有效地,但不强制执行)与Person的1:1关系和Position与自身有关系:{{1}是FK到PositionID

SupervisorPositionID

为什么CREATE TABLE [dbo].[Position]( [PositionID] [int] IDENTITY(1,1) NOT NULL, [PositionNumber] [varchar](8) NULL, [Title] [varchar](40) NULL, [Division] [varchar](40) NULL, [Section] [varchar](40) NULL, [Unit] [varchar](40) NULL, [SupervisorPositionID] [int] NULL, ) CREATE TABLE [dbo].[Person]( [PersonID] [int] IDENTITY(1,1) NOT NULL, [PersonnelNumber] [varchar](8) NOT NULL, [LastName] [varchar](40) NULL, [FirstName] [varchar](40) NULL, [MiddleInitial] [char](1) NULL, [PositionID] [int] NULL, ) 会附加到此行的末尾,我该怎么做才能修复它?

2 个答案:

答案 0 :(得分:1)

您需要更改DbContext上的设置。该属性为UseDatabaseNullSemantics,您需要将其设置为false

context.Configuration.UseDatabaseNullSemantics = false;

答案 1 :(得分:1)

我目前没有任何工具来检查这是否会产生所需的输出,但我认为它应该足够接近:

            from a in Persons
            join b in Positions on a.PositionID equals b.PositionID
            join c in Positions on b.SupervisorPositionID equals c.PositionID into SupervisorsPositions
                from c in SupervisorsPositions.DefaultIfEmpty()
            join d in Persons on c.PositionID equals d.PositionID into PersonalNumbers
                from d in PersonalNumbers.DefaultIfEmpty()
            select new { 
                            a.PersonnelNumber, 
                            a.LastName, 
                            a.FirstName, 
                            a.MiddleInitial, 
                            b.Title, 
                            b.Division, 
                            b.Section, 
                            b.Unit, 
                            SupervisorPersonnelNumber = d.PersonnelNumber
                       }

此查询将生成:

SELECT [t0].[PersonnelNumber], [t0].[LastName], [t0].[FirstName], [t0].[MiddleInitial], [t1].[Title], [t1].[Division], [t1].[Section], [t1].[Unit], [t3].[PersonnelNumber] AS [SupervisorPersonnelNumber]
FROM [Person] AS [t0]
INNER JOIN [Position] AS [t1] ON [t0].[PositionID] = ([t1].[PositionID])
LEFT OUTER JOIN [Position] AS [t2] ON [t1].[SupervisorPositionID] = ([t2].[PositionID])
LEFT OUTER JOIN [Person] AS [t3] ON ([t2].[PositionID]) = [t3].[PositionID]

T-SQL language specification LEFT OUTER JOIN等于LEFT JOIN。 INNER JOIN等于JOIN。

这样查询就会生成您需要的结果。有关T-SQL中的连接类型的更多信息,请参阅that answer