如何使用AutoMapper将基础类型Id映射到实现IEntity接口的对象属性
解决方案
配置失效原因
你之前的配置存在两处核心问题:
- 源类型判断错误:代码中判断
mapConfiguration.SourceType == typeof(int),但你实际使用的Id类型为Guid,无法匹配到对应映射规则 - 规则作用范围错误:
ForAllMaps仅会作用于已经创建的类型映射,你没有预先为Guid和所有IEntity实现类创建映射,规则没有可匹配的目标对象
全局映射实现代码
通过反射扫描所有IEntity实现类,批量创建基础Id类型到实体的映射即可满足需求:
using AutoMapper; using System.Reflection; interface IEntity { Guid Id { get; set; } } public class Comment : IEntity { public Guid Id { get; set; } } public class User : IEntity { public Guid Id { get; set; } public List<Comment> Comments { get; set; } } public class LinkUserWithCommentsCommand { public Guid Id { get; set; } public List<Guid> CommentIds { get; set; } } public class MappingProfile : Profile { public MappingProfile() { // 扫描所有程序集中实现了IEntity的非抽象实体类 var entityTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes()) .Where(t => typeof(IEntity).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract) .ToList(); // 获取CreateMap泛型方法定义 var createMapMethod = typeof(Profile) .GetMethods(BindingFlags.Instance | BindingFlags.Public) .First(m => m.Name == nameof(CreateMap) && m.GetParameters().Length == 0); foreach (var entityType in entityTypes) { // 构造 Guid -> 实体 的映射配置 var genericCreateMap = createMapMethod.MakeGenericMethod(typeof(Guid), entityType); var mappingExp = genericCreateMap.Invoke(this, null); // 配置Id字段映射逻辑:直接将源Guid赋值给实体Id属性 var forMemberMethod = mappingExp.GetType() .GetMethods() .First(m => m.Name == nameof(IMappingExpression<object, object>.ForMember) && m.GetParameters().Length == 2); forMemberMethod.Invoke(mappingExp, new object[] { nameof(IEntity.Id), new Action<IMemberConfigurationExpression<Guid, object, object>>(opt => opt.MapFrom(src => src)) }); } // 配置命令类到User的映射,AutoMapper会自动匹配命名规则:CommentIds → Comments CreateMap<LinkUserWithCommentsCommand, User>(); } }
验证说明
AutoMapper默认支持集合属性名匹配规则,后缀为Ids的源集合属性,会自动匹配到去掉Ids后缀的同名目标集合属性,你场景中的CommentIds刚好对应Comments,结合我们已经配置的单个Guid到Comment的映射,框架会自动完成集合元素的转换。
测试代码如下:
var config = new MapperConfiguration(cfg => cfg.AddProfile<MappingProfile>()); var mapper = config.CreateMapper(); var command = new LinkUserWithCommentsCommand { Id = Guid.NewGuid(), CommentIds = new List<Guid> { Guid.NewGuid(), Guid.NewGuid() } }; var user = mapper.Map<User>(command); // user.Id 与 command.Id 相等 // user.Comments 集合中每个Comment的Id,对应command.CommentIds中的值
如果你的集合属性命名不符合默认规则,手动指定映射关系即可:
CreateMap<LinkUserWithCommentsCommand, User>() .ForMember(dest => dest.Comments, opt => opt.MapFrom(src => src.YourCustomIdListName));
如需支持int、long等其他Id类型,在循环中按照同样逻辑新增对应类型的映射即可。
内容的提问来源于stack exchange,提问作者Hnus
相关产品推荐
相关产品推荐

