将 SQL 转换为带有 null 的 Linq 左连接

Posted

技术标签:

【中文标题】将 SQL 转换为带有 null 的 Linq 左连接【英文标题】:Convert SQL to Linq left join with null 【发布时间】:2012-02-07 04:35:49 【问题描述】:

我怎样才能正确地将这个 SQL 转换为 linq

select  t1.ProgramID
from Program t1 LEFT JOIN ProgramLocation t2 ON  t1.ProgramID = t2.ProgramID 
where t2.ProgramID IS NULL

我试过了,还是不行

var progy = (
             from u in db.ProgramLocations join b in db.Programs
             on u.ProgramID equals b.ProgramID into yG 
             from y1 in yG.DefaultIfEmpty() 
             where u.ProgramID == null
             where u.ProgramID == null 
             select u.ProgramID
            ).ToList();

谢谢

【问题讨论】:

试过linqpad.net? 这会将 SQL 转换为 LINQ 【参考方案1】:

你想使用.DefaultIfEmpty,就像this question一样。

var query = from p in Programs
            join pl in ProgramLocations
                on p.ProgramID equals pl.ProgramID into pp
            from pl in pp.DefaultIfEmpty()
            where pl == null
            select p;

这是一个包含一些模拟数据对象的完整工作示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqTest

    class LinqProgram
    
        public class Program
        
            public int ProgramID  get; set; 
            public string ProgramName  get; set; 
        

        public class ProgramLocation
        
            public int ProgramLocationID  get; set; 
            public int ProgramID  get; set; 
            public string ProgramLocationName  get; set; 
        

        public static List<Program> Programs = new List<Program>();
        public static List<ProgramLocation> ProgramLocations = new List<ProgramLocation>();

        static void Main(string[] args)
        
            FillTestData();

            var query = from p in Programs
                        join pl in ProgramLocations
                            on p.ProgramID equals pl.ProgramID into pp
                        from pl in pp.DefaultIfEmpty()
                        where pl == null
                        select p;

            foreach (var r in query)
            
                Console.WriteLine("0: 1", r.ProgramID, r.ProgramName);
            

            Console.ReadLine();
        

        private static void FillTestData()
        
            var p = new Program()
            
                ProgramID = Programs.Count + 1,
                ProgramName = "Scary Lesson"
            ;
            var pl = new ProgramLocation()
            
                ProgramLocationID = ProgramLocations.Count + 1,
                ProgramID = p.ProgramID,
                ProgramLocationName = "Haunted House"
            ;
            Programs.Add(p);
            ProgramLocations.Add(pl);

            p = new Program()
            
                ProgramID = Programs.Count + 1,
                ProgramName = "Terrifying Teachings"
            ;

            pl = new ProgramLocation()
            
                ProgramLocationID = ProgramLocations.Count + 1,
                ProgramID = p.ProgramID,
                ProgramLocationName = "Mystical Mansion"
            ;
            Programs.Add(p);
            ProgramLocations.Add(pl);

            p = new Program()
            
                ProgramID = Programs.Count + 1,
                ProgramName = "Unassociated Program"
            ;
            Programs.Add(p);
        
    

【讨论】:

【参考方案2】:

试试这个

  var progy = (
         from u in db.ProgramLocations join b in db.Programs
         on u.ProgramID equals b.ProgramID into yG 
         from y1 in yG.DefaultIfEmpty() 
         where y1 == null
         select u.ProgramID
        ).ToList();

您可以查看this post on MSDN。

希望这对你有用。

【讨论】:

【参考方案3】:

你能用 except 代替吗?

var progy = (
  from u in db.ProgramLocations
  select u.ProgramID
).Except(from b in db.Programs select b.ProgramID);

【讨论】:

这只有在 ProgramID 是您需要检索的唯一值时才有效。【参考方案4】:
SELECT pfa.PetID, pt.PetTypeDesc, pfa.petname, pf.PetOwner, pf.remarks, pat.AdoptedBy
    FROM dbo.PetForAdoption pfa
    JOIN dbo.PetAdoptionTran pat
    ON pfa.PetID = pat.PetID
    JOIN dbo.PetTypes pt 
    ON pfa.PetTypeID = pt.PetTypeID
    JOIN dbo.PetProfile pf
    ON pfa.PetID = pf.PetID
    ORDER BY pt.PetTypeDesc

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。请阅读此how-to-answer 以提供高质量的答案。【参考方案5】:

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

林克:

var recs=from programs in db.Programs
         from locations in db.ProgramLocations.where(x=> x.ProgramID == programs.ProgramID).DefaultIfEmpty()
         where locations.ProgramID == null  //Compiler creates a warning because int will never be null, but it works and creates outer left join
         select programs.ProgramID;

生成的 SQL:

SELECT 
"Extent1"."ProgramID" AS "ProgramID"
FROM "DBO"."Program" "Extent1"
LEFT OUTER JOIN "DBO"."ProgramLocation" "Extent2" ON "Extent2"."ProgramID" = "Extent1"."ProgramID"
WHERE ("Extent2"."ProgramID" IS NULL)

如果您有多个连接条件,这也适用并且也适用于多个左连接

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

【讨论】:

以上是关于将 SQL 转换为带有 null 的 Linq 左连接的主要内容,如果未能解决你的问题,请参考以下文章

C# 将带有 Case 语句的 SQL 查询转换为 LINQ

如何将带有 LEFT JOIN 的 SQL 转换为 EF CORE 3 LINQ

将 SQL 转换为 LINQ 方法表达式

Linq to Sql 左连接 , 取右表可能为 null的 int类型字段

Linq中向实体左联接的Sql查询

如何将以下 linq 查询转换为 SQL 中的 (Having)