You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中Join两个集合:如何获取双集合全量数据而非仅匹配项

嘿,我懂你现在的困惑——LINQ里默认的Join方法其实是内连接,只会返回两个集合里能匹配上的元素,这就是为啥你拿不到两边的全部数据。要实现类似SQL里的「全外连接」(FULL OUTER JOIN),得换个思路来写,我给你两种实用的解决方案,都是用原生LINQ就能搞定的:

先假设你的数据结构(方便示例)

先定义两个简单的实体类,模拟你要合并的集合:

// 用户集合的实体
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// 订单集合的实体
public class Order
{
    public int UserId { get; set; }
    public string OrderNumber { get; set; }
}

解决方案1:用GroupJoin + SelectMany 实现全外连接

这种方法通过左连接+右连接再合并的方式,覆盖所有数据:

// 初始化测试数据
var users = new List<User>
{
    new User { Id = 1, Name = "Alice" },
    new User { Id = 2, Name = "Bob" },
    new User { Id = 3, Name = "Charlie" }
};

var orders = new List<Order>
{
    new Order { UserId = 1, OrderNumber = "ORD001" },
    new Order { UserId = 2, OrderNumber = "ORD002" },
    new Order { UserId = 4, OrderNumber = "ORD003" }
};

// 第一步:左连接——拿到所有用户,以及他们对应的订单(没有订单的用户显示null)
var leftJoin = users.GroupJoin(
    orders,
    user => user.Id,          // 用户集合的匹配键
    order => order.UserId,    // 订单集合的匹配键
    (user, userOrders) => new { User = user, Orders = userOrders.DefaultIfEmpty() }
).SelectMany(
    x => x.Orders,
    (x, order) => new { User = x.User, Order = order }
);

// 第二步:右连接——拿到所有订单,以及它们对应的用户(没有用户的订单显示null)
var rightJoin = orders.GroupJoin(
    users,
    order => order.UserId,
    user => user.Id,
    (order, orderUsers) => new { Order = order, Users = orderUsers.DefaultIfEmpty() }
).SelectMany(
    x => x.Users,
    (x, user) => new { User = user, Order = x.Order }
);

// 第三步:合并左右连接结果,去重得到全外连接
var fullOuterJoin = leftJoin.Union(rightJoin);

代码说明:

  • GroupJoin会把左边集合的元素和右边匹配的元素分组,DefaultIfEmpty()确保没有匹配项时也会返回null,不会漏掉元素。
  • SelectMany把分组后的结果展开成扁平的集合。
  • Union自动去重,避免重复的匹配项同时出现在左连接和右连接中。

解决方案2:拆分合并(内连接 + 两边未匹配项)

这种方法更直观,分开处理「匹配项」「左边未匹配项」「右边未匹配项」,再合并:

// 第一步:拿到两个集合的匹配项(就是默认Join的结果)
var matchedItems = users.Join(
    orders,
    u => u.Id,
    o => o.UserId,
    (u, o) => new { User = u, Order = o }
);

// 第二步:拿到没有对应订单的用户
var usersWithoutOrders = users
    .Where(u => !orders.Any(o => o.UserId == u.Id))
    .Select(u => new { User = u, Order = (Order)null });

// 第三步:拿到没有对应用户的订单
var ordersWithoutUsers = orders
    .Where(o => !users.Any(u => u.Id == o.UserId))
    .Select(o => new { User = (User)null, Order = o });

// 第四步:合并所有结果
var fullOuterJoin = matchedItems.Concat(usersWithoutOrders).Concat(ordersWithoutUsers);

代码说明:

  • 先通过Join拿到所有匹配的元素,再分别筛选出两边没有匹配的元素,最后用Concat把三个部分合并起来。
  • 这种写法逻辑清晰,适合刚接触LINQ的开发者理解。

小提示

  • 如果你的集合里有重复的匹配键,记得根据业务需求处理去重逻辑。
  • 如果是值类型(比如int),要注意null的处理(可以用可空类型int?)。

内容的提问来源于stack exchange,提问作者Wojciech Pierscionek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:19:12