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

使用AutoMapper的ProjectTo时如何过滤子记录?

问题场景

给定如下DTO与映射接口:

public record EntityDto : IMapFrom<Entity>
{
    ...

    public List<Child> Children { get; init; } = new();

    public void Mapping(Profile profile)
    {
        profile.CreateMap<Entity, EntityDto>()
            .ForMember(m => m.Children, opt => opt.MapFrom(s => s.Children.Where(x => x.CreatedAt == childrenFilter ???)));
    }
}

public interface IMapFrom<T>
{
    void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}

在通过AutoMapper的ProjectTo进行实体投影时,需要利用外部定义的childrenFilter变量过滤DTO中的子集合Children,仅保留符合条件的子项:

var childrenFilter = DateTime.Now;

var entity = await _dbContext.Entity
    .ProjectTo<EntityDto>(_mapper.ConfigurationProvider)
    .ToListAsync(cancellationToken);
解决方案

AutoMapper的映射配置(Mapping方法)属于初始化阶段执行的代码,无法直接引用运行时才会生成的childrenFilter变量,可通过以下两种方式实现需求:

方法一:使用AutoMapper运行时上下文参数

  1. 修改映射配置
    在MapFrom中通过ResolutionContext获取运行时传入的过滤参数:
public void Mapping(Profile profile)
{
    profile.CreateMap<Entity, EntityDto>()
        .ForMember(m => m.Children, opt => opt.MapFrom((source, _, context) => 
            source.Children.Where(x => x.CreatedAt == (DateTime)context.Items["ChildrenFilter"])));
}
  1. 投影时传入参数
    调用ProjectTo时,通过第二个参数传入包含过滤条件的上下文字典:
var childrenFilter = DateTime.Now;

var entities = await _dbContext.Entity
    .ProjectTo<EntityDto>(_mapper.ConfigurationProvider, 
        new Dictionary<string, object> { ["ChildrenFilter"] = childrenFilter })
    .ToListAsync(cancellationToken);

为避免魔法字符串,可封装强类型扩展方法优化:

public static class ResolutionContextExtensions
{
    public static DateTime GetChildrenFilter(this ResolutionContext context)
    {
        return (DateTime)context.Items["ChildrenFilter"];
    }
}

修改映射配置为:

.ForMember(m => m.Children, opt => opt.MapFrom((source, _, context) => 
    source.Children.Where(x => x.CreatedAt == context.GetChildrenFilter())));

方法二:直接在LINQ查询中手动投影

如果不需要统一通过AutoMapper配置处理,可直接在查询阶段对子集合过滤后再映射:

var childrenFilter = DateTime.Now;

var entities = await _dbContext.Entity
    .Select(e => new EntityDto
    {
        // 映射其他实体属性
        ...,
        Children = e.Children.Where(x => x.CreatedAt == childrenFilter).ToList()
    })
    .ToListAsync(cancellationToken);

这种方式跳过AutoMapper的映射配置,适合简单场景。

注意事项

  • 确保过滤条件x.CreatedAt == childrenFilter能被EF Core正确解析为SQL语句,避免客户端评估导致的性能问题;
  • 若使用方法一,需保证context.Items中存在指定键的参数,可添加空值判断避免运行时异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 03:32:28