【问题标题】:Linq Left Join where right is nullLinq Left Join,其中 right 为空
【发布时间】:2016-10-13 13:56:20
【问题描述】:

相对较新的 linq,来自 SQL。因此,我正在尝试找出以下内容的左连接:

SELECT * from MASTER m
LEFT JOIN CHILD C
    ON m.ID=C.MASTER_ID
WHERE C.MASTER_ID is null

所以,通常这会返回来自 Master 的所有没有孩子的记录。我发现了 .DefualtIfEmpty() 但这并没有消除有孩子的主记录。

我是这样开始的:

var recs=from m in MASTER
         from c in child
             .where (mapping=>mapping.MasterId == m.Id)
             .DefaultIfEmpty()
         select new { MasterId = m.Id};

但这就是我所得到的并且被卡住了。我假设 .DefaultIfEmpty() 不是我想要的。 注意:主表中有几百万行。孩子们的人数接近相同。我之所以提及,是因为拉回所有记录等效率不高。理想情况下,生成的 SQL 将看起来像我发布的 SQL。

谢谢大家。

【问题讨论】:

标签: c# .net linq linq-to-sql


【解决方案1】:

如果您使用的是 EF,那么您可以使用代表子级的导航属性来获取没有子级的主控:

var result= from m in MASTER
            where m.Children.Count()==0// or m.Any()
            select m;

如果你想在 linq 中使用显式连接,你可以试试这个:

var recs=from m in MASTER
         join c in child on m.Id equals C.MasterId into gj
         where gj.Count()==0 // or gj.Any()
         select m;

【讨论】:

  • 我也喜欢这种方法,但我没有在这个特定项目中使用 EF。但是,我还有其他我确实使用过的东西,我会在这些项目中这样做。谢谢。
【解决方案2】:

这将为您提供所有没有子项的主记录。

var recs = MASTER.Where(x => !child.Any(y => m.Id == c.MasterId));

!Any 将生成一个not Exists SQL 语句,该语句将在执行计划中被翻译成一个anti semi join,这是您可以得到的最佳此类检查。

【讨论】:

  • 我查看了它生成的 SQL 的查询计划,它看起来已经尽可能优化了。现在有了一些放置良好的索引,我想我会是金子。谢谢。
【解决方案3】:

您可以使用 Linq 执行左外连接

var leftJoinResult = from m in MASTER join c in CHILD 
                   on m.ID equals  C.MASTER_ID 
                   into a
                   from b in a.DefaultIfEmpty()
                   select new {MASTER = m,
                               CHILD = b};

然后消除有孩子的主记录

var result=leftJoinResult.where(x=>x.CHILD == null).select(y=>y.MASTER).ToList();

【讨论】:

    【解决方案4】:

    我遇到了同样的问题。仅当您至少有一行子项时,此解决方案才有效。行的 ID 无关紧要。

    var recs=from m in MASTER
             from c in child
                 .where (mapping=>mapping.MasterId == m.Id)
                 .DefaultIfEmpty() into fullC
             select new { MasterId = m.Id};
    

    关键字 into 具有魔力。添加它会显示所有行,包括那些在 c 中具有 NULL 值的行。

    【讨论】:

      【解决方案5】:

      我现在遇到了这个问题,整洁的 SQL 是必须的,并且以非常优化的方式运行。

      林克:

      var recs=from m in MASTER
               from c in child.where (mapping=>mapping.MasterId == m.Id).DefaultIfEmpty()
               where c.Id == null  //Compiler creates a warning because int will never be null, but it works and creates outer left join
               select new { MasterId = m.Id};
      

      生成的 SQL:

      SELECT 
      "Extent1"."Id" AS "MasterId"
      FROM "DBO"."Master" "Extent1"
      LEFT OUTER JOIN "DBO"."Child" "Extent2" ON "Extent2"."MasterId" = "Extent1"."Id"
      WHERE ("Extent2"."Id" IS NULL)
      

      如果您有多个连接条件,这也有效 并且还可以为多个左连接工作

      ps。我将 EF 与 Oracle 一起使用,因此不确定这在 EF 的 SQLServer 提供程序上是否会略有不同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-04
        • 1970-01-01
        • 1970-01-01
        • 2011-03-12
        • 1970-01-01
        • 1970-01-01
        • 2013-05-02
        相关资源
        最近更新 更多