如何配置AutoMapper实现List到HashSet的集合类型映射?
这问题我之前也碰到过!AutoMapper默认确实会跟着源集合的类型走,把你的HashSet换成List,不过有两种简单的方法解决,要么针对单个映射配置,要么全局统一设置,我给你一步步讲:
解决方案1:针对单个映射配置(精准控制)
因为你的Machine类已经在构造函数里把Segment初始化为HashSet<Segment>了,我们只需要告诉AutoMapper不要替换这个已有的集合实例,而是把DTO里的元素添加进去就行。修改你的映射代码:
// 先配置Segment与SegmentDto的双向映射 cfg.CreateMap<SegmentDto, Segment>(); cfg.CreateMap<Segment, SegmentDto>(); // 配置MachineDto到Machine的映射,指定集合属性复用目标已有的实例 cfg.CreateMap<MachineDto, Machine>(MemberList.Source) .ForMember(dest => dest.Segment, opt => opt.UseDestinationValue()); // 反向映射同理 cfg.CreateMap<Machine, MachineDto>(MemberList.Destination) .ForMember(dest => dest.Segment, opt => opt.UseDestinationValue());
原理:UseDestinationValue()告诉AutoMapper,不要创建新的集合(默认会跟着源的List创建List),而是复用目标对象(这里是Machine实例)中已经存在的集合,也就是你构造函数里初始化的HashSet。
解决方案2:全局配置(一劳永逸)
如果你的项目里有很多类似的实体,不想逐个配置每个集合属性,可以用全局规则,让所有ICollection<T>类型的目标属性都复用已有的实例:
// 先配置Segment与SegmentDto的双向映射 cfg.CreateMap<SegmentDto, Segment>(); cfg.CreateMap<Segment, SegmentDto>(); // 全局规则:对所有ICollection类型的属性,使用目标已有的集合实例 cfg.ForAllMaps((map, exp) => { exp.ForAllMembers(opt => { if (opt.DestinationMember != null && typeof(ICollection<>).IsAssignableFrom(opt.DestinationMember.Type)) { opt.UseDestinationValue(); } }); }); // 正常创建你的双向映射即可 cfg.CreateMap<MachineDto, Machine>(MemberList.Source); cfg.CreateMap<Machine, MachineDto>(MemberList.Destination);
这样不管有多少个实体,只要是ICollection类型的属性,都会自动复用目标对象里初始化的集合实例(前提是你在实体构造函数里把集合初始化为HashSet)。
验证效果
写个简单的测试代码确认一下:
var machineDto = new MachineDto { ID = 1, Name = "Test Machine", Segment = new List<SegmentDto> { new SegmentDto { ID = 1, Serial = "Seg001" }, new SegmentDto { ID = 2, Serial = "Seg002" } } }; var mapper = cfg.CreateMapper(); var machine = mapper.Map<Machine>(machineDto); // 输出HashSet`1,说明集合类型保持正确 Console.WriteLine(machine.Segment.GetType().Name);
这样就解决了AutoMapper把HashSet替换成List的问题啦!
内容的提问来源于stack exchange,提问作者Jesse
相关产品推荐
相关产品推荐

