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

EF Core:如何直接通过查询为Parent类赋值子项统计数,避免循环

问题描述

我定义了两个实体类:Parent(可包含0个或多个Child)和Child,代码如下:

public class Parent()
{
   int ID { get; set; }
   string Name { get; set; }
   int NumberOfChildren { get; set; }
}

以及

public class Child()
{
   int ID { get; set; }
   int ParentID { get; set; }
   string Name { get; set; }
}

目前我通过EF查询获取所有Parent记录并填充NumberOfChildren属性,代码如下:

List<Parent> parentList = [];

var tempList = await context.Parents
                            .GroupJoin(context.Children, 
                                       p => p.ID, 
                                       c => c.ParentID, 
                                       (p, c) => new { Parent = p, ChildCount = c.Count() })
                            .ToListAsync();

foreach (var item in tempList)
{
    item.Parent.NumberOfChildren = item.ChildCount;
    parentList.Add(item.Parent);
}

这种循环更新NumberOfChildren的方式看起来效率较低,请问能否在EF查询中直接设置该属性值,无需循环即可直接得到赋值后的List<Parent>集合?

解决方案

当然可以,你可以直接在EF查询的投影阶段完成NumberOfChildren的赋值,省去后续循环操作,以下是两种可行方案:

方案1:直接投影构造Parent对象

在GroupJoin的结果选择器中,直接创建Parent实例并赋值所有属性,包括计算得到的子项数量:

List<Parent> parentList = await context.Parents
    .GroupJoin(context.Children,
        p => p.ID,
        c => c.ParentID,
        (p, children) => new Parent
        {
            ID = p.ID,
            Name = p.Name,
            NumberOfChildren = children.Count()
        })
    .ToListAsync();

该方案会让EF在数据库层面完成分组统计,直接将结果映射为已赋值NumberOfChildren的Parent集合,无需额外处理。

方案2:修改现有Parent实体属性(需注意跟踪状态)

如果需要保留EF对实体的跟踪(比如后续要修改保存),可以在查询中直接修改原实体的属性:

List<Parent> parentList = await context.Parents
    .GroupJoin(context.Children,
        p => p.ID,
        c => c.ParentID,
        (p, children) => new { Parent = p, ChildCount = children.Count() })
    .Select(x => 
    {
        x.Parent.NumberOfChildren = x.ChildCount;
        return x.Parent;
    })
    .ToListAsync();

此方案会先完成数据库端的分组统计,在结果加载到本地后直接为每个Parent实体赋值NumberOfChildren,最终返回处理好的集合。需要注意:EF会将这些实体标记为已修改状态,若后续调用SaveChangesAsync(),会把NumberOfChildren的更新写入数据库;如果不需要保存该计算属性,可在查询后调用context.Entry(parent).State = EntityState.Unchanged;取消跟踪。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 05:26:07