如何在 C# 中使用 linq 扩展方法执行左外连接?

来源:Python编程网作者:柬埔寨程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《如何在 C# 中使用 linq 扩展方法执行左外连接?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在 C# 中使用 linq 扩展方法执行左外连接?》有用,将其分享出去将是对创作者最好的鼓励。

在C#的关系型数据查询场景中,左外连接是常用的关联操作,它会返回左集合的所有元素,即使右集合中不存在匹配的元素,对应右集合的字段会返回默认值。使用linq扩展方法实现左外连接不需要编写复杂的循环逻辑,通过组合内置的扩展方法就能快速完成。

如何在 C# 中使用 linq 扩展方法执行左外连接?

左外连接的核心实现思路

linq本身没有直接提供左外连接的扩展方法,但是可以通过GroupJoinSelectMany两个扩展方法的组合来实现。核心逻辑分为两步:第一步用GroupJoin将左集合和右集合按照关联键分组,得到左集合每个元素对应的右集合元素分组;第二步用SelectMany展开分组,对没有匹配右元素的左元素补充默认值。

基础数据准备

首先定义两个简单的数据实体类,模拟需要关联的两张数据表:

// 学生实体类
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int ClassId { get; set; }
}

// 班级实体类
public class Class
{
    public int Id { get; set; }
    public string ClassName { get; set; }
}

然后初始化测试数据:

// 学生列表,包含属于不同班级的学生,还有一个学生没有对应班级
List<Student> students = new List<Student>
{
    new Student { Id = 1, Name = "张三", ClassId = 1 },
    new Student { Id = 2, Name = "李四", ClassId = 1 },
    new Student { Id = 3, Name = "王五", ClassId = 2 },
    new Student { Id = 4, Name = "赵六", ClassId = 3 } // 3号班级不在班级列表中
};

// 班级列表
List<Class> classes = new List<Class>
{
    new Class { Id = 1, ClassName = "一年级一班" },
    new Class { Id = 2, ClassName = "一年级二班" }
};

使用linq扩展方法实现左外连接

下面是完整的左外连接实现代码,会返回所有学生信息,以及对应的班级名称,没有对应班级的学生班级名称显示为null:

var leftJoinResult = students
    // 第一步:GroupJoin 按ClassId关联,得到每个学生的对应班级分组
    .GroupJoin(
        classes, // 右集合
        s => s.ClassId, // 左集合的关联键
        c => c.Id, // 右集合的关联键
        (s, classGroup) => new { Student = s, ClassGroup = classGroup } // 结果投影
    )
    // 第二步:SelectMany 展开分组,处理无匹配的情况
    .SelectMany(
        temp => temp.ClassGroup.DefaultIfEmpty(), // 如果分组为空,返回默认值(null)
        (temp, c) => new // 最终投影结果
        {
            StudentId = temp.Student.Id,
            StudentName = temp.Student.Name,
            ClassName = c == null ? null : c.ClassName
        }
    );

// 输出结果验证
foreach (var item in leftJoinResult)
{
    Console.WriteLine($"学生ID:{item.StudentId},姓名:{item.StudentName},班级:{item.ClassName ?? "无对应班级"}");
}

运行上述代码后,输出结果如下:

学生ID:1,姓名:张三,班级:一年级一班
学生ID:2,姓名:李四,班级:一年级一班
学生ID:3,姓名:王五,班级:一年级二班
学生ID:4,姓名:赵六,班级:无对应班级

关键点说明

  • GroupJoin的第四个参数是结果选择器,这里我们把左元素和对应的右元素分组一起返回,方便后续处理。
  • DefaultIfEmpty方法的作用是当分组中没有元素时,返回一个包含默认值的序列,对于引用类型来说默认值就是null。
  • 如果右集合的元素是值类型,比如关联的是int类型的字段,那么DefaultIfEmpty可以传入自定义的默认值,避免返回0导致歧义。

和查询表达式写法的对比

linq也支持查询表达式的写法实现左外连接,核心逻辑和扩展方法一致,以下是等价的查询表达式代码:

var queryResult = from s in students
                  join c in classes on s.ClassId equals c.Id into classGroup
                  from c in classGroup.DefaultIfEmpty()
                  select new
                  {
                      StudentId = s.Id,
                      StudentName = s.Name,
                      ClassName = c == null ? null : c.ClassName
                  };

两种写法最终的执行结果完全一致,扩展方法写法更适合在需要链式调用多个linq操作的场景使用,查询表达式写法更接近SQL的语法,可读性更强,开发者可以根据习惯选择。

C#linq左外连接扩展方法GroupJoin修改时间:2026-07-05 19:54:24

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。