左连接查询未按预期工作

时间:2011-10-19 06:55:30

标签: linq-to-entities entity-framework-4.1

如何在Linq中将此查询写入实体:

SELECT * FROM TableA a LEFT JOIN TableB b ON a.Id = b.TableAId WHERE ISNULL(b.Id) OR b.FieldA = 1

关系是1对多,但限制b.FIeldA = 1确保返回的实际数据为1-0 ... 1,这意味着返回的记录数应等于TableA中的记录。我需要从TableA获取所有数据,并从TableB中加入存在的数据。我正在尝试使用这个查询,它实际上像INNER JOIN一样预先形成(TableA中的记录没有在TableB中没有相关记录)

Vladislav建议在下面查询,我在第一次查询中添加了额外的过滤:

var query = (from x in myParentClasses.Include(x => x.TableBChildren)
         where !x.TableBChildren.Any(y => y.FieldA == 1)
         select x)
        .Concat(
         from x in myParentClasses.Include(x => x.TableBChildren)
         where x.TableBChildren.Any(y => y.FieldA == 1 || y.Id == null)
         select x)
        .ToList();

生成的sql如下所示:

SELECT   [Project1][...]
FROM     (SELECT [Extent1].[...],
                 [Extent2].[...],
                 [Extent3].[...],
                 CASE 
                   WHEN ([Extent3].[Id] IS NULL) THEN CAST(NULL AS int)
                   ELSE 1
                 END AS [C1]
          FROM   [dbo].[ParentTable] AS [Extent1]
                 LEFT OUTER JOIN [dbo].[ReferenceTable] AS [Extent2]
                   ON [Extent1].[ReferenceId] = [Extent2].[Id]
                 LEFT OUTER JOIN [dbo].[ChildrenTable] AS [Extent3]
                   ON [Extent1].[Id] = [Extent3].[ParentId]
          WHERE  [Extent1].[FieldA] = 1 /* @p__linq__0 */) AS [Project1]
ORDER BY [Project1].[Id] ASC,
         [Project1].[Id1] ASC,
         [Project1].[C1] ASC

谢谢, 戈兰

1 个答案:

答案 0 :(得分:0)

Linq-to-entities与SQL完全不同。只有在您的查询允许时才执行左连接(除非您手动编写连接,否则您无法手动控制该行为)。这不是您的查询的情况,因为它使用x.TableBChildren.Any =它要求父表具有满足条件的子表中的任何记录,因此它使用内部联接。

我没有尝试过,可能有更好的方法,但我认为这可行:

var query = (from x in myParentClasses.Include(x => x.TableBChildren)
             where !x.TableBChildren.Any()
             select x)
            .Concat(
             from x in myParentClasses.Include(x => x.TableBChildren)
             where x.TableBChildren.Any(y => y.FieldA == 1 || y.Id == null)
             select x)
            .ToList();

第一部分选择所有没有相关实体的记录,第二部分选择满足条件的相关实体的记录。它将这两部分联合起来。

另请注意,Include不会过滤您的关系 - 它会每次都选择所有关系。如果你想过滤它们,你必须用投影编写查询。

编辑:

如果您希望过滤TableB,则无法使用普通查询和Include。您也无法返回MyParentClass的实例。你必须使用投影:

var query = from x in myParentClasses
            select new 
              {
                  Id = x.Id,
                  // Rest of properties from myParentClass you want to receive
                  TableBChildren = x.TableBChildren.Where(y => y.FieldA == 1 || y.Id == null)
              };

这将返回带有过滤的TableB s的匿名类型。无法投影到映射实体(MyParentClass)。

相关问题