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

如何使用IQueryable.Select将嵌套对象列表展平为多条记录?

解决方案:将Parent-Children一对多结构扁平化为多条记录

当然可行!这其实就是把一对多的父子结构“扁平化”成多条平级记录的需求,用EF的SelectMany就能轻松实现,我给你一步步讲清楚:

1. 先明确实体和目标模型结构

假设你的实体类大概是这样的:

public class Parent
{
    public int Id { get; set; }
    public string ParentName { get; set; }
    // 其他Parent属性...
    public ICollection<Child> Children { get; set; }
}

public class Child
{
    public int Id { get; set; }
    public string ChildName { get; set; }
    public int ParentId { get; set; }
    // 其他Child属性...
}

我们要生成的目标模型(包含Parent所有属性+单个Child属性):

public class ParentChildViewModel
{
    // 映射Parent的所有属性
    public int ParentId { get; set; }
    public string ParentName { get; set; }
    // 映射单个Child的属性
    public int ChildId { get; set; }
    public string ChildName { get; set; }
    // 其他需要的属性...
}

2. 核心实现:用SelectMany展开Children集合

SelectMany的作用就是把集合中的每个元素(这里是Parent的Children)“拆出来”,和父元素(Parent)配对,形成一对一的组合。这样每个Child都会对应一条包含完整Parent属性的记录。

直接投影到ViewModel的写法:

var flattenedResult = dbContext.Parents
    .SelectMany(
        parent => parent.Children, // 取出当前Parent的所有Children
        (parent, child) => new ParentChildViewModel // 把Parent和单个Child组合成目标模型
        {
            ParentId = parent.Id,
            ParentName = parent.ParentName,
            ChildId = child.Id,
            ChildName = child.ChildName
            // 填充其他属性...
        })
    .ToList();

结合你的BuildModel()方法的写法:

如果你的BuildModel是用来封装ViewModel构建逻辑的,只需要调整成接收Parent和Child两个参数:

// 先定义支持双参数的BuildModel方法
private ParentChildViewModel BuildModel(Parent parent, Child child)
{
    return new ParentChildViewModel
    {
        ParentId = parent.Id,
        ParentName = parent.ParentName,
        ChildId = child.Id,
        ChildName = child.ChildName
        // 其他属性映射逻辑...
    };
}

// 查询时调用
var flattenedResult = dbContext.Parents
    .SelectMany(parent => parent.Children, (parent, child) => BuildModel(parent, child))
    .ToList();

3. 处理没有Children的Parent(可选)

如果有些Parent没有Children,上面的写法会自动过滤掉这些Parent。如果想保留它们(返回Child属性为null的记录),只需要给Children加上DefaultIfEmpty():

var flattenedResult = dbContext.Parents
    .SelectMany(
        parent => parent.Children.DefaultIfEmpty(), // 空集合时返回默认值(null)
        (parent, child) => BuildModel(parent, child))
    .ToList();

关键说明

这种方式是在数据库层面完成的(EF会把SelectMany翻译成SQL的JOIN语句),不会把所有Parent和Children加载到内存再处理,性能非常高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:37:41