使用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运行时上下文参数
- 修改映射配置
在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"]))); }
- 投影时传入参数
调用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
相关产品推荐
相关产品推荐

