我有一个Dto,看起来像这样:
class TypeDto
{
int Id {get; set;}
string Name {get; set;}
string DisplayName {get; set;}
IEnumerable<TypeDto> Children {get; set;}
}
现在,我需要从两个不同的来源映射到它.这是因为其中一个包含Name,另一个包含DisplayName.所以类型:
class Type1
{
int Id {get; set;}
string Name {get; set;}
IEnumerable<Type1> Children {get; set;}
}
class Type2
{
int Id {get; set;}
string DisplayName {get; set;}
IEnumerable<Type2> Nested {get; set;}
}
注意“儿童/嵌套”枚举中的名称差异.
现在为地图做:
config.CreateMap<Type1, TypeDto>();
config.CreateMap<Type2, TypeDto>()
.ForMember(dest => dest.Children, opts => opts.MapFrom(src => src.Nested));
var dto = _mapper.Map<TypeDto>(type1Instance);
_mapper.Map(type2Instance, dto);
第一个映射按预期工作,递归映射子代,填充Id和Name字段,并在所有地方使DisplayName等于null.但是,第二个映射正确地为根对象填充了DisplayName,但是在其子对象中,它使Name字段无效.因此,例如:
var type1Instance = new Type1
{
Id = 1,
Name = "root",
Children = new[] { new Type1
{
Id = 2,
Name = "child"
}}
};
var type2Instance = new Type2
{
Id = 1,
DisplayName = "Root",
Children = new[] { new Type2
{
Id = 2,
DisplayName = "Child"
}}
};
映射以下实例后,结果将其字段设置为:
Id = 1,
Name = "root",
DisplayName = "Root",
Children = { TypeDto { Id = 2, Name = null, DisplayName = "Child", Children = null } }
所以孩子的名字无效了,那不是我想要的.显然,我希望它是“孩子”.我应该如何配置映射器以获得所需的行为?
我无法更改Type1或Type2类,它们来自外部API.
AutoMapper的版本是6.2.1,.NET Framework 4.5.1.
解决方法:
摘自Lucian Bargaoanu的评论.
AutoMapper.Collection包解决了我的问题.所需要做的只是将此语句添加到配置中:
config.AddCollectionMappers();
然后在两张地图上定义EqualityComparison:
config.CreateMap<Type1, TypeDto>()
.EqualityComparison((src, dest) => src.Id == dest.Id);
config.CreateMap<Type2, TypeDto>()
.EqualityComparison((src, dest) => src.Id == dest.Id)
.ForMember(dest => dest.Children, opts => opts.MapFrom(src => src.Nested));
之后,集合将正确更新.引用来自here的文档,第二个映射即
_mapper.Map(type2Instance, dto);
现在将在具有匹配ID的任何集合成员上递归映射,添加到集合并映射type2Instance.Nested中dto.Children集合中未出现的所有项目,并删除dto.Children包含但type2Instance.Nested没有的任何项目.