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

使用三个实体时LINQ GroupBy与Sum的运行时翻译问题求助

解决EF Core中GroupBy嵌套Sum无法翻译的问题

EF Core无法将你原代码中GroupBy后的嵌套Sum(r => r.Payments.Where(...).Sum(...))结构正确翻译为SQL,这种多层聚合的写法超出了当前EF Core的SQL转换能力。以下两种单查询方案可以解决问题,同时保持你需要的输出结构:

方案一:先投影结算级支付金额再分组汇总

先在单个Settlement层面计算对应两种支付类型的总额,再基于驾驶员信息分组求和:

var settlementsGrouped = await _databaseContext.Settlements
    .ExcludeDeleted()
    .Where(s => s.DriverId == request.Id && s.DateStart >= request.DateStart && s.DateEnd <= request.DateEnd)
    .Select(s => new 
    {
        DriverInfo = new { s.Driver.Id, s.Driver.FullName, s.Driver.Address, s.Driver.PostalCode, s.Driver.Town, s.Driver.IdNumber },
        CommonPayment = s.Payments.Where(p => p.IsActive && p.Type == PaymentEntityTypeEnum.Common).Sum(p => p.Amount),
        AdvancePayment = s.Payments.Where(p => p.IsActive && p.Type == PaymentEntityTypeEnum.Advance).Sum(p => p.Amount)
    })
    .GroupBy(x => x.DriverInfo)
    .Select(g => new 
    {
        g.Key.FullName,
        g.Key.Address,
        g.Key.PostalCode,
        g.Key.Town,
        g.Key.IdNumber,
        PaymentType = g.Sum(x => x.CommonPayment),
        AdvancePaymentType = g.Sum(x => x.AdvancePayment)
    })
    .ToListAsync(cancellationToken);

这种写法把嵌套聚合拆成了两层单层聚合,EF Core可以正确转换为对应的SQL分组统计逻辑。

方案二:展开Payments后分组统计

通过SelectMany将结算和关联支付展开为扁平结构,再按驾驶员信息分组并按支付类型求和:

var settlementsGrouped = await _databaseContext.Settlements
    .ExcludeDeleted()
    .Where(s => s.DriverId == request.Id && s.DateStart >= request.DateStart && s.DateEnd <= request.DateEnd)
    .SelectMany(s => s.Payments.Where(p => p.IsActive), (s, p) => new 
    {
        s.Driver.FullName,
        s.Driver.Address,
        s.Driver.PostalCode,
        s.Driver.Town,
        s.Driver.IdNumber,
        p.Type,
        p.Amount
    })
    .GroupBy(x => new { x.FullName, x.Address, x.PostalCode, x.Town, x.IdNumber })
    .Select(g => new 
    {
        g.Key.FullName,
        g.Key.Address,
        g.Key.PostalCode,
        g.Key.Town,
        g.Key.IdNumber,
        PaymentType = g.Where(x => x.Type == PaymentEntityTypeEnum.Common).Sum(x => x.Amount),
        AdvancePaymentType = g.Where(x => x.Type == PaymentEntityTypeEnum.Advance).Sum(x => x.Amount)
    })
    .ToListAsync(cancellationToken);

该方案通过扁平化关联数据,将聚合操作简化为分组内的条件求和,同样能被EF Core正确翻译。

两种方案都保持了数据库端查询的特性,不会触发客户端评估,且当某个结算无对应类型支付时,Sum会返回0,和原逻辑一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 01:05:22