dotnet 10 LINQ LeftJoin & RightJoin

dotnet 10 LINQ LeftJoin & RightJoin

Intro

.NET 10 Preview 1 为 LINQ 支持了 LeftJoinRightJoin,此前我们只支持 Join,需要自己实现,在 .NET 10 中将内置 LeftJoin/RightJoin 并且 EF 也将为之提供支持

New API

新增 API 如下:

代码语言:javascript代码运行次数:0运行复制
namespace System.Linq;

publicstaticclassEnumerable
{
    publicstatic IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,  
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter, TInner?, TResult> resultSelector);

    publicstatic IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,  
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter, TInner?, TResult> resultSelector,
        IEqualityComparer<TKey>? comparer);

    publicstatic IEnumerable<TResult> RightJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,  
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter?, TInner, TResult> resultSelector);

    publicstatic IEnumerable<TResult> RightJoin<TOuter, TInner, TKey, TResult>(
        this IEnumerable<TOuter> outer,  
        IEnumerable<TInner> inner,
        Func<TOuter, TKey> outerKeySelector,
        Func<TInner, TKey> innerKeySelector,
        Func<TOuter?, TInner, TResult> resultSelector,
        IEqualityComparer<TKey>? comparer);
}

publicstaticclassQueryable
{
    publicstatic IQueryable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IQueryable<TOuter> outer,
        IEnumerable<TInner> inner,
        Expression<Func<TOuter, TKey>> outerKeySelector,
        Expression<Func<TInner, TKey>> innerKeySelector,
        Expression<Func<TOuter, TInner?, TResult>> resultSelector);

    publicstatic IQueryable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(
        this IQueryable<TOuter> outer,
        IEnumerable<TInner> inner,
        Expression<Func<TOuter, TKey>> outerKeySelector,
        Expression<Func<TInner, TKey>> innerKeySelector,
        Expression<Func<TOuter, TInner?, TResult>> resultSelector,
        IEqualityComparer<TKey>? comparer);
    
    publicstatic IQueryable<TResult> RightJoin<TOuter, TInner, TKey, TResult>(
        this IQueryable<TOuter> outer,
        IEnumerable<TInner> inner,
        Expression<Func<TOuter, TKey>> outerKeySelector,
        Expression<Func<TInner, TKey>> innerKeySelector,
        Expression<Func<TOuter?, TInner, TResult>> resultSelector);

    publicstatic IQueryable<TResult> RightJoin<TOuter, TInner, TKey, TResult>(
        this IQueryable<TOuter> outer,
        IEnumerable<TInner> inner,
        Expression<Func<TOuter, TKey>> outerKeySelector,
        Expression<Func<TInner, TKey>> innerKeySelector,
        Expression<Func<TOuter?, TInner, TResult>> resultSelector,
        IEqualityComparer<TKey>? comparer);
}

Sample

使用起来和 Join 类似,只是 LeftJoin/RightJoin 的时候可能会 map 不到数据导致有数据可能会 null,使用起来也是非常的简单,下面是一个简单的使用示例:

代码语言:javascript代码运行次数:0运行复制
var jobs = new[]
{
    new
    {
        Id = 1,
        Name = "test"
    }
};
var employeeList = new[]
{
    new
    {
        Id = 1,
        JobId = 1,
        Name = "Alice"
    },
    new
    {
        Id = 2,
        JobId = 2,
        Name = "Jane"
    }
};
var result = employeeList.LeftJoin(jobs, e => e.JobId, j => j.Id, (e, j) => new
{
    e.Id,
    e.Name,
    e.JobId,
    JobName = j?.Name ?? "Unnamed"
});
foreach (var item in result)
{
    Console.WriteLine(JsonSerializer.Serialize(item));
}

这里两个员工对应两个 job 但是 job collection 里只有一个 job,会导致 left join 的时候,job 可能会为 null,我们设置了 JobName 在 Job 为 null 时显示为 Unnamed,执行结果如下:

left-join output

类似地我们也可以使用 right join

代码语言:javascript代码运行次数:0运行复制
foreach (var item in jobs.RightJoin(employeeList, j => j.Id, e => e.JobId, (j, e) => new
        {
            e.Id,
            e.Name,
            e.JobId,
            JobName = j?.Name ?? "Unknown"
        }))
        {
            Console.WriteLine(JsonSerializer.Serialize(item));
        }

输出结果如下:

代码语言:javascript代码运行次数:0运行复制
{"Id":1,"Name":"Alice","JobId":1,"JobName":"test"}
{"Id":2,"Name":"Jane","JobId":2,"JobName":"Unknown"}

More

如果要在已有的项目里使用,可以在自己的项目里实现一个扩展方法,实现代码如下:

代码语言:javascript代码运行次数:0运行复制
public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,
    IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
    Func<TOuter, TInner?, TResult> resultSelector)
{
    return outer
        .GroupJoin(inner, outerKeySelector, innerKeySelector,
            (outerObj, inners) => new { outerObj, inners = inners.DefaultIfEmpty() })
        .SelectMany(a => a.inners.Select(innerObj => resultSelector(a.outerObj, innerObj)));
}

References

  • .linq.enumerable.join
  • .cs
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-18,如有侵权请联系 cloudcommunity@tencent 删除ampexpressionfunclinq数据