我有一个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;}
}
请注意Children
/ Nested
枚举中的名称差异。
现在我要做的地图:
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 } }
所以孩子的Name
无效了,那不是我想要的。显然,我希望它是"child"
。我应该如何配置映射器以获得所需的行为?
我无法更改Type1
或Type2
类,它们来自外部API。
AutoMapper的版本是6.2.1,.NET Framework 4.5.1。
答案 0 :(得分:2)
摘自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
集合中未出现的所有项目,并删除所有{ {1}}包含,但dto.Children
不包含。
答案 1 :(得分:1)
这是我认为的一种可能的解决方案:
config.CreateMap<Type2, TypeDto>()
.ForMember(dest => dest.Children, opts => opts.Ignore())
.AfterMap((d,e) => AddNestedChildren(d, e));
private void AddNestedChildren(Type2 type, TypeDto dto)
{
foreach (var child in type.Nested)
{
var childDto = dto.Children.SingleOrDefault(c => c.Id == child.Id);
// keep old properties
Mapper.Map(child, childDto);
}
}
如评论中所述,默认情况下集合无效。我可以找到解决您问题的一种方法,就是使用AfterMap
来手动遍历child / nested集合,找到另一个集合的对应子对象(通过ID或您发现相关的任何其他属性),并手动将其映射。
我基本上使用了my answer to this question中的相同想法。