user380689 user380689 - 14 days ago 6
C# Question

AutoMapper Ignore on child collection property

I am trying to map object's of the same type which have a collection of child objects and am finding that Ignore() applied to properties on the child object seem to be umm... ignored!

Here's a unit test which demonstrates the problem.

class A
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<B> Children { get; set; }
}

class B
{
public int Id { get; set; }
public string Name { get; set; }
}

[TestClass]
public class UnitTest1
{
[TestInitialize()]
public void Initialize()
{
Mapper.CreateMap<A, A>()
.ForMember(dest => dest.Id, opt => opt.Ignore());

Mapper.CreateMap<B, B>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
}

[TestMethod]
public void TestMethod1()
{
A src = new A { Id = 0, Name = "Source", Children = new List<B> { new B { Id = 0, Name = "Child Src" } } };
A dest = new A { Id = 1, Name = "Dest", Children = new List<B> { new B { Id = 11, Name = "Child Dest" } } };

Mapper.Map(src, dest);

}


After the Map call the A object's Id property is still 1, as expected, but child B object's Id property is changed from 11 to 0.

Why?

Answer

There are several bugs in AutoMapper 4.1.1.

First is about UseDestinationValue: https://github.com/AutoMapper/AutoMapper/issues/568

Second is about nested collections: https://github.com/AutoMapper/AutoMapper/issues/934

Horrifying! The workaround is to map your B instances directly:

Mapper.CreateMap<A, A>()
    .ForMember(dest => dest.Id, opt => opt.Ignore())
    .ForMember(dest => dest.Children, opt => opt.Ignore());

Mapper.CreateMap<B, B>()
    .ForMember(dest => dest.Id, opt => opt.Condition((ResolutionContext src) => false));

and add additional mapping calls:

Mapper.Map(src, dest);
Mapper.Map(src.Children.First(), dest.Children.First()); //example!!!

You may call Mapper.Map in cycle:

for (int i = 0; i < src.Children.Count; i++)
{
    var srcChild = src.Children[i];
    var destChild = dest.Children[i];

    Mapper.Map(srcChild, destChild);
}

This will make things work right.