I have a Dto that looks somewhat like this:
class TypeDto
{
int Id {get; set;}
string Name {get; set;}
string DisplayName {get; set;}
IEnumerable<TypeDto> Children {get; set;}
}
Now I need to map to it from two different sources. That's because one of them contains Name
and the other contains DisplayName
. So the types:
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;}
}
Notice the name difference in the Children
/Nested
enumerable.
Now for the map I would do:
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);
The first map works as expected, mapping the children recursively, filling the Id
and Name
fields and leaving DisplayName
equal to null
everywhere. The second map, however, fills in the DisplayName
for the root object properly, but then in its children, it nullifies the Name
field. So for example:
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"
}}
};
After mapping the following instances the resultant has its fields set to:
Id = 1,
Name = "root",
DisplayName = "Root",
Children = { TypeDto { Id = 2, Name = null, DisplayName = "Child", Children = null } }
so the child's Name
is nullified, and that's not what I want. I'd like it to be "child"
, obviously. How should I configure the mapper to get the wanted behavior?
I cannot change the Type1
or Type2
classes, they're from an external API.
AutoMapper's version is 6.2.1, .NET Framework 4.5.1.
Taken from Lucian Bargaoanu's comment.
The AutoMapper.Collection
package solves my problem. All that was needed is adding this statement to configuration:
config.AddCollectionMappers();
and then defining EqualityComparison on both my maps:
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));
After that the collections are properly updated. Citing the docs from here, the second mapping, i.e.
_mapper.Map(type2Instance, dto);
will now map recursively on any collection members with matching Id
, add to the collection and map any items from type2Instance.Nested
which do not occur in dto.Children
collection and remove any items that dto.Children
contains, but type2Instance.Nested
does not.