🔥

【LINQ】3つ以上のオブジェクトを結合する時のTips

に公開

はじめに

最近、気付いたLINQのTipsです。Tipsというほどでもありませんが・・・。
今までは3つ以上のオブジェクトを結合する時に中間テーブルに結合後の値を全て列挙していました。5つくらいのオブジェクトを結合する時は最終的に必要になる値を中間テーブルにも全部列挙しており、コード量が膨大になりがちだったのですが、コンパクトに書ける方法を知りました。

データモデル

モデルに特に意味はありません。ChatGPTに作成してもらいました。

public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; } = null!;
    public string Position { get; set; } = null!;
}

public class Project
{
    public int ProjectId { get; set; }
    public int EmployeeId { get; set; }
    public string Name { get; set; } = null!;
    public string? Description { get; set; }
}

public class Task
{
    public int TaskId { get; set; }
    public int ProjectId { get; set; }
    public string Title { get; set; } = null!;
    public string? Description { get; set; }
    public bool IsCompleted { get; set; } = false;
    public DateTime DueDate { get; set; }
}

全列挙バージョン

var result = employees.Join(projects,
    e => e.EmployeeId,
    p => p.EmployeeId,
    (employee, project) => new
    {
    // ここで最終的に必要になる値を全部列挙している
        EmployeeId = employee.EmployeeId,
        ProjectId = project.ProjectId,
        EmployeeName = employee.Name,
        EmployeePosition = employee.Position,
        ProjectName = project.Name,
        ProjectDescription = project.Description,
    }).Join(tasks,
    joined => joined.ProjectId,
    t => t.ProjectId,
    (joined, task) => new
    {
        EmployeeId = joined.EmployeeId,
        ProjectId = joined.ProjectId,
        EmployeeName = joined.EmployeeName,
        EmployeePosition = joined.EmployeePosition,
        ProjectName = joined.ProjectName,
        ProjectDescription = joined.ProjectDescription,
        TaskName = task.Title,
        TaskCompleted = task.IsCompleted,
        DueDate = task.DueDate,
    }).ToList();

コンパクトバージョン

var result = employees.Join(projects,
    e => e.EmployeeId,
    p => p.EmployeeId,
    (employee, project) => new { employee, project } 
    ).Join(tasks,
    x => x.project.ProjectId,
    t => t.ProjectId,
    (x, task) => new
    {
        EmployeeId = x.employee.EmployeeId,
        ProjectId = x.project.ProjectId,
        EmployeeName = x.employee.Name,
        EmployeePosition = x.employee.Position,
        ProjectName = x.project.Name,
        ProjectDescription = x.project.Description,
        TaskName = x.project.Name,
        TaskCompleted = task.IsCompleted,
        DueDate = task.DueDate
    }).ToList();

Discussion