C# 自动映射覆盖递归类型
我有一个Dto,看起来有点像这样:C# 自动映射覆盖递归类型,c#,.net,automapper,automapper-6,C#,.net,Automapper,Automapper 6,我有一个Dto,看起来有点像这样: class TypeDto { int Id {get; set;} string Name {get; set;} string DisplayName {get; set;} IEnumerable<TypeDto> Children {get; set;} } 请注意子项/嵌套可枚举项中的名称差异 现在,对于地图,我要做: config.CreateMap<Type1, TypeDto>(
class TypeDto
{
int Id {get; set;}
string Name {get; set;}
string DisplayName {get; set;}
IEnumerable<TypeDto> Children {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 = 1,
Name = "root",
DisplayName = "Root",
Children = { TypeDto { Id = 2, Name = null, DisplayName = "Child", Children = null } }
所以孩子的名字无效,这不是我想要的。显然,我希望它是“child”
。我应该如何配置映射程序以获得所需的行为
我无法更改Type1
或Type2
类,它们来自外部API
AutoMapper的版本是6.2.1、.NET Framework 4.5.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);
}
}
config.CreateMap()
.FormMember(dest=>dest.Children,opts=>opts.Ignore())
.AfterMap((d,e)=>AddNestedChildren(d,e));
私有void AddNestedChildren(Type2类型,TypeDto到dto)
{
foreach(type.Nested中的变量子级)
{
var childDto=dto.Children.SingleOrDefault(c=>c.Id==child.Id);
//保留旧财产
Mapper.Map(child,childDto);
}
}
如注释中所述,集合默认为空。对于您的问题,我可以找到一个解决方案,即使用AfterMap
手动循环子集合/嵌套集合,找到另一个集合的对应子集合(通过Id或您认为相关的任何其他属性),然后手动映射它
我基本上使用了来自卢西恩·巴加奥努评论的相同想法
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));
现在将递归映射到具有匹配的Id
的任何集合成员上,将type2Instance.Nested
中未出现在dto.Children
集合中的所有项添加到集合中,并映射到dto.Children
集合中的所有项,但是type2Instance.Nested
不会。首先清除集合,请选中AutoMapper.Collection。Check.AutoMapper.Collection解决了这个问题。在所有映射之间通过Id
添加EqualityComparison
,可使AutoMapper正确更新集合。你能把这个评论变成一个答案,这样我就可以接受了吗?你可以自己发布答案。不起作用。此外,我认为AutoMapper不会触及映射源中不存在的属性(因此根对象的名称已填充)。@V0ldek您已经提到,实际上AutoMapper应该抛出一个异常,因为它要求您映射目标类型中的所有属性。查看我编辑过的答案,让我知道这是否对您有帮助。AutoMapper.Collection
也有类似的功能,所以我去用了它(请参阅基于Lucian Bargaonanu评论的“我的”答案)。谢谢你的解决方案。这个解决方案真的很好很干净。这比我的答案还要简单,谢谢分享。
config.AddCollectionMappers();
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));
_mapper.Map(type2Instance, dto);