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

LINQ使用Union合并两表数据时如何按ProductNumber填充缺失字段值

问题原因

你当前写法的问题出在Union的两个分支上:查询Products表时,把订单相关的OrderNumber、Amount字段硬编码为0;查询OrderItems表时,又把产品基础属性Cost、Price、Name、Inventory硬编码为0或空串。Union 本身只负责合并两个结果集、对完全重复的行去重,不会自动匹配相同ProductNumber的记录补全空缺字段,最终结果自然会出现大量字段为默认空值的情况。

推荐实现方案

不要硬编码空值再事后补数,直接以Products表(存储产品固定属性)为主表左连接OrderItems表(存储订单关联数据),一次投影就能生成完整字段的结果,需要手动指定特定产品的字段值时,直接在投影逻辑里加判断即可,所有计算可以直接在数据库侧完成,性能更好。

方法语法版本代码:

var test = db.Products
    .GroupJoin(
        db.OrderItems,
        p => p.ProductNumber,
        oi => oi.ProductNumber,
        (p, orderItems) => new { Product = p, OrderItems = orderItems }
    )
    .SelectMany(
        x => x.OrderItems.DefaultIfEmpty(),
        (x, oi) => new UnionTable
        {
            ProductNumber = x.Product.ProductNumber,
            OrderNumber = oi?.OrderNumber ?? 0,
            Cost = x.Product.Cost,
            // 针对ProductNumber=1的记录单独指定Price和Name,其余产品取表内存储值
            Price = x.Product.ProductNumber == 1 ? 10 : x.Product.Price,
            Name = x.Product.ProductNumber == 1 ? "almond" : x.Product.Name,
            Amount = oi?.Amount ?? 0,
            Inventory = x.Product.Inventory
        }
    )
    .ToList();

查询语法版本代码:

var test = 
    from p in db.Products
    join oi in db.OrderItems on p.ProductNumber equals oi.ProductNumber into oiGroup
    from orderItem in oiGroup.DefaultIfEmpty()
    select new UnionTable
    {
        ProductNumber = p.ProductNumber,
        OrderNumber = orderItem?.OrderNumber ?? 0,
        Cost = p.Cost,
        Price = p.ProductNumber == 1 ? 10 : p.Price,
        Name = p.ProductNumber == 1 ? "almond" : p.Name,
        Amount = orderItem?.Amount ?? 0,
        Inventory = p.Inventory
    };
兼容原有Union写法的补全方案

如果你因为业务逻辑必须保留先Union的结构,可以在Union结果的基础上,按ProductNumber分组,取同组内对应字段的非默认值填充,手动指定的固定值也可以在这一步统一赋值:

// 原有Union查询逻辑不变
var rawData = 
    (from table1 in db.Products
     select new UnionTable()
     {
         ProductNumber = table1.ProductNumber,
         OrderNumber = 0,
         Cost = table1.Cost,
         Price = table1.Price,
         Name = table1.Name,
         Amount = 0,
         Inventory = table1.Inventory
     }).Union
     (from table2 in db.OrderItems
      select new UnionTable()
      {
          ProductNumber = table2.ProductNumber,
          OrderNumber = table2.OrderNumber,
          Cost = 0,
          Price = 0,
          Name = string.Empty,
          Amount = table2.Amount,
          Inventory = 0
      });

// 二次聚合补全字段
var test = rawData
    .GroupBy(r => r.ProductNumber)
    .Select(g => new UnionTable
    {
        ProductNumber = g.Key,
        OrderNumber = g.Max(r => r.OrderNumber),
        Cost = g.Max(r => r.Cost),
        Price = g.Key == 1 ? 10 : g.Max(r => r.Price),
        Name = g.Key == 1 ? "almond" : g.First(r => !string.IsNullOrEmpty(r.Name)).Name,
        Amount = g.Max(r => r.Amount),
        Inventory = g.Max(r => r.Inventory)
    })
    .ToList();

注意:优先选第一种Join写法,这种方式不需要拉取大量带硬编码空值的冗余数据,数据库执行效率比先Union再内存聚合高很多,数据量越大优势越明显。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:12:25