Is there any way to get AutoMapper.Collection to skip the mapping of a collection if the source collection property is null?
In my case, the client may want to signal to the API that there is no need to update a given collection. A logical way do this would be to set the collection property to null in the dto sent from the client.
Basically:
- If the source collection property is null: Do not touch the destination collection at all but leave it as-is. Do not clear it
- If the source collection is not null: Do the collection mapping. If the source collection is empty this means clearing the destination collection
Is there any way to achieve this in AutoMapper.Collection? What I am looking for is this:
// Sample Classes
public class Entity
{
public ICollection<EntityChild> Children { get; set; }
}
public class EntityChild
{
public int Id { get; set; }
public string Value { get; set; }
}
public class Dto
{
public ICollection<DtoChild> Children { get; set; }
}
public class DtoChild
{
public int Id { get; set; }
public string Value { get; set; }
}
// AutoMapper setup including equality for children
CreateMap<Dto, Entity>();
CreateMap<DtoChild, EntityChild>()
.EqualityComparison((src, dst) => src.Id == dst.Id)
.ReverseMap();
// Sample 1, null source collection
var entity = new Entity
{
Children = new List<EntityChild>
{
new() { Id = 1, Value = "Value 1" },
new() { Id = 2, Value = "Value 2" }
}
};
var dtoSkipChildren = new Dto
{
Children = null
};
// Since the source Children property is null, do not update the destination collection
mapper.Map(dtoSkipChildren, entity);
// Sample 2, empty source collection
entity = new Entity
{
Children = new List<EntityChild>
{
new() { Id = 1, Value = "Value 1" },
new() { Id = 2, Value = "Value 2" }
}
};
var dtoClearChildren = new Dto
{
Children = new List<DtoChild>()
};
// Now the source children is not null (but empty) so the destination collection should
// be updated (in this case cleared since the source collection is empty)
mapper.Map(dtoClearChildren, entity);
AutoMapper.Collection treats the null source Children property the same as the source Children property containing an empty collection. In both cases the destination Children collection is cleared.
I have tried to tell AutoMapper to skip the source.Children property if null:
CreateMap<Dto, Entity>()
.ForMember(dst => dst.Children, opt => opt.Condition(src => null != src.Children));
This does not change things. Also in this case, the source collection property is null when AutoMapper.Collection sets to work and the destination collection is cleared.
This is not a real solution either:
CreateMap<Dto, Entity>()
.ForMember(
src => src.Children,
opt => opt.MapFrom((src, dst, _, ctx) => src.Children ?? ctx.Mapper.Map<ICollection<DtoChild>>(dst.Children)));
This means reverse mapping the destination collection to the (null) source collection, so it can be mapped back. An ugly hack:
- It's crossing the river twice to end up where you started
- Wasted effort which is silly on large collections
- Risky as the reverse map for other reasons may not be 100% thus introducing pretty hidden bugs
Does anyone have an advice on how to achieve this - or why my use case is not a good idea?