Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analyzer/codefix to transform older GroupJoin/SelectMany pattern to the new .NET 10 LeftJoin #7570

Open
Tracked by #35379
roji opened this issue Feb 10, 2025 · 0 comments

Comments

@roji
Copy link
Member

roji commented Feb 10, 2025

.NET 10 is introducing LINQ LeftJoin and RightJoin operators, similar to the Join operator (see dotnet/runtime#110292). The new LeftJoin operator is intended to replace the traditional way of expressing a left join operation, as shown in the LINQ docs:

var query = students
    .GroupJoin(
        departments,
        student => student.DepartmentID,
        department => department.ID,
        (student, departmentList) => new { student, subgroup = departmentList })
    .SelectMany(
        joinedSet => joinedSet.subgroup.DefaultIfEmpty(),
        (student, department) => new
        {
            student.student.FirstName,
            student.student.LastName,
            Department = department.Name
        });

This combination of GroupJoin/SelectMany/DefaultIfEmpty() is both comlex/verbose, and inefficient (see #110292 for some benchmark figures). In .NET 10, the above can be replaced with the following simpler (and more efficient) code:

var query = students.LeftJoin(
    departments,
    s => s.DepartmentID,
    d => d.Id,
    (s, d) => new
    {
        s.FirstName,
        s.LastName,
        DepartmentName = d.Name
    });

We can introduce an analyzer to pattern-match the GroupJoin/SelectMany/DefaultIfEmpty construct, and a codefix to transform it to the below LeftJoin construct.

In addition, dotnet/csharplang#8947 proposes a corresponding C# language change, adding left join (and right join) within LINQ query (comprehension) syntax:

from student in students
left join department in departments on student.DepartmentID equals department.ID
select new { student.Name, Department = department?.Name }

Again, this can replace the older pattern:

var query =
    from student in students
    join department in departments on student.DepartmentID equals department.ID into gj
    from subgroup in gj.DefaultIfEmpty()
    select new
    {
        student.Name,
        Department = subgroup?.Name
    };

Assuming this makes sense, it's something I'd be happy to work on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant