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

EF Core使用GroupBy后Include预加载集合为空的原因及解决方法

EF Core分组后Include集合为空的原因与解决方案

问题代码

var productsByRecalls = await _context
  .Products
  .Include(x => x.Suppliers)                              // <-----
  .Include(x => x.Recalls)                                // <-----
  .AsSplitQuery()
  .OrderBy(x => x.CreatedAt)
  .Where(x => x.Status == ProductStatus.Approved)
  .GroupBy(x => x.Recalls)                                // <-----
  .Where(x => x.Any()).Select(x => x.SingleOrDefault())
  .ToListAsync();

问题原因

EF Core中,数据库层面的GroupBy操作会直接破坏预加载(Include)的关联数据逻辑:

  1. SQL原生的GROUP BY仅支持返回分组键和聚合计算结果,无法直接返回包含集合类型的完整实体;
  2. 当你按Recalls(集合导航属性)分组时,EF Core会将查询转换为SQL的GROUP BY,但集合无法作为有效的分组键,导致后续Select(x => x.SingleOrDefault())获取到的Product实体丢失了之前通过Include预加载的Suppliers和Recalls关联数据——分组操作已经中断了EF Core对关联实体的追踪和加载逻辑。

解决方案

根据数据量大小,可选择以下两种方案:

方案1:内存中分组(适合小数据量)

先将所有符合条件的Product及其关联数据完整加载到内存,再执行分组操作,避免数据库层面分组破坏关联:

// 先加载所有符合条件的Product及关联数据
var allApprovedProducts = await _context
    .Products
    .Include(x => x.Suppliers)
    .Include(x => x.Recalls)
    .AsSplitQuery()
    .OrderBy(x => x.CreatedAt)
    .Where(x => x.Status == ProductStatus.Approved)
    .ToListAsync();

// 在内存中分组并取每组的单个Product
var productsByRecalls = allApprovedProducts
    .GroupBy(x => x.Recalls)
    .Where(g => g.Any())
    .Select(g => g.FirstOrDefault())
    .ToList();

方案2:分两步数据库查询(适合大数据量)

先在数据库层面获取分组对应的ProductId,再根据ID查询完整实体并预加载关联,避免一次性加载大量数据:

// 第一步:获取每个Recalls分组对应的目标ProductId
var targetProductIds = await _context
    .Products
    .Where(x => x.Status == ProductStatus.Approved)
    // 关联Recalls并按Recall的标识分组(假设Recalls有Id属性)
    .SelectMany(x => x.Recalls.Select(r => new { ProductId = x.Id, RecallId = r.Id }))
    .GroupBy(x => x.RecallId)
    .Where(g => g.Any())
    .Select(g => g.First().ProductId)
    .ToListAsync();

// 第二步:根据ID查询完整Product并预加载关联
var productsByRecalls = await _context
    .Products
    .Include(x => x.Suppliers)
    .Include(x => x.Recalls)
    .AsSplitQuery()
    .Where(x => targetProductIds.Contains(x.Id))
    .OrderBy(x => x.CreatedAt)
    .ToListAsync();

关键说明

EF Core的GroupBy分为两种执行模式:

  • 数据库层面执行:仅支持返回分组键和聚合值,无法保留实体的关联集合;
  • 内存层面执行:先加载完整实体数据,再在内存中分组,能保留所有关联数据,但需注意内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 07:22:37