如何在AutoMapper中为相同类型对同时注册实例映射与查询投影
解决AutoMapper中同时支持实例映射与查询投影的问题
嘿,我完全理解你遇到的困惑——AutoMapper的CreateMap和CreateProjection确实容易让人误以为需要分开配置,但其实这里有个关键知识点你可能没注意到:你根本不需要同时调用这两个方法!
问题根源
当你同时为同一组类型对调用CreateMap和CreateProjection时,AutoMapper会将CreateProjection的配置视为该类型对的专属投影规则,但这会干扰实例映射的逻辑。当你尝试用Map方法转换内存中的实体时,AutoMapper会检测到存在投影配置,却找不到对应的实例映射规则(或者两者冲突),于是就抛出了那个“CreateProjection works with ProjectTo, not with Map”的错误。
正确的配置方式
AutoMapper的CreateMap方法本身就同时支持实例映射(Map方法)和查询投影(ProjectTo方法)。你只需要保留一份CreateMap配置,就能同时满足两种场景的需求:
// 只需要这一行,同时支持Map和ProjectTo CreateMap<UserSession, Models.UserSession>();
这样配置后:
- 当你从EF获取到物化的
UserSession实体,调用mapper.Map<Models.UserSession>(userSession)时,AutoMapper会使用实例映射逻辑完成转换。 - 当你在IQueryable上调用
.ProjectTo<Models.UserSession>(mapper.ConfigurationProvider)时,AutoMapper会自动生成对应的SQL投影语句,和之前用CreateProjection的效果完全一致。
进阶:投影专属配置
如果你需要为投影场景设置特殊规则(比如某些字段只在投影时忽略、使用数据库端的计算逻辑等),可以通过ConfigureProjection方法在CreateMap的基础上扩展投影专属配置,而不需要单独调用CreateProjection:
CreateMap<UserSession, Models.UserSession>() // 共享的映射规则,同时适用于Map和ProjectTo .ForMember(dest => dest.LastActiveTime, opt => opt.MapFrom(src => src.LastUpdated)) // 仅针对ProjectTo的专属配置 .ConfigureProjection(proj => proj .ForMember(dest => dest.SessionDuration, opt => opt.MapFrom(src => EF.Functions.DateDiffSecond(src.CreatedAt, src.LastUpdated))) .ForMember(dest => dest.IsExpired, opt => opt.MapFrom(src => src.ExpiresAt < DateTime.UtcNow)));
这种方式既保留了实例映射的逻辑,又能为查询投影添加专属的转换规则,完美解决两种场景的需求。
总结一下
- 删除单独的
CreateProjection<UserSession, Models.UserSession>()调用; - 只保留
CreateMap<UserSession, Models.UserSession>()的基础配置; - 如果需要投影专属规则,用
ConfigureProjection扩展配置; - 测试
Map和ProjectTo两种场景,确认都能正常工作。
这样就能避免你遇到的错误,同时让AutoMapper在两种场景下都能正确识别并使用对应的映射规则。
内容的提问来源于stack exchange,提问作者Thanasis Ioannidis
相关产品推荐
相关产品推荐

