When AutoMapper encounters an object that\'s already been mapped, it seems to use that object again, instead of trying to re-map it. I believe it does this based on .Equal
It seems that the Equals behaviour of the tree object you're mapping is inappropriate.
The method should only return true if "the specified object is equal to the current object." - http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx
In your case, you have two tree objects sharing the same id but clearly, they are not "equal" since they have different children.
I suggest looking at why the Equals method has been abused in this way and whether you could get the behaviour you need by not overriding the Equals method, instead using a different method to check the tree id field with a more appropriate name eg. TreeIdsAreEqual.
I also get the same issue. It doesn't happen when you map the same object twice - it happens when you have a tree heirarcy of objects, and the same value exists in two places of the tree (but with different child values) When mapping the second instance of the item - it uses the child values of the first instance, instead of re-evaluating what the child values should be.
Here is my example:
class Tag {
int Id {get; set;}
string Name {get; set;}
IEnumerable<Tag> ChildTags {get; set;}
}
public void Test()
{
var source = new List<Tag>
{
new Tag { Id = 1, Name = "Tag 1", ChildTags = new List<Tag>
{
new Tag { Id = 2, Name = "Tag 2", ChildTags = new List<Tag>
{
new Tag {Id = 3, Name = "Tag 3"},
new Tag {Id = 4, Name = "Tag 4"}
}
}
}
},
new Tag { Id = 1, Name = "Tag 1" },
new Tag {
Id = 3, Name = "Tag 3", ChildTags = new List<Tag>
{
new Tag {Id = 4, Name = "Tag 4"}
}
}
};
Mapper.CreateMap<Tag, Tag>()
.ForMember(dest => dest.ChildTags,
opt => opt.MapFrom(src => src.ChildTags));
var result = Mapper.Map<IList<Tag>, IList<Tag>>(tags);
}
In the result
the first instance of Tag 1 (ie source[0]) and all of its children are perfect
the second instance of Tag 1 (ie source[1]) has all the children of the first instance - it should not have any children
the second instance of Tag 3 (ie source[2]) does not have any children - it should have Tag 4 as a child
I've faced the same issue with the mapper, looking around i found that a solution for it, by adding
Mapper.Reset();
Source blog (corrected URL)
When AutoMapper encounters an object that's already been mapped, it seems to use that object again, instead of trying to re-map it. I believe it does this based on .Equals()
Can you explain why and when you see that ?
After a quick look in the source code, I'm sure there is no cache for objects. Here is a test that illustrate this :
public class CustomerSource
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public int NumberOfOrders { get; set; }
}
public class CustomerTarget
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public int NumberOfOrders { get; set; }
}
[TestMethod]
public void Test_AutoMapper()
{
Mapper.CreateMap<CustomerSource, CustomerTarget>();
var source = new CustomerSource() { DateOfBirth = DateTime.Now, FirstName = "FirstName", LastName = "LastName", NumberOfOrders = int.MaxValue };
var res1 = Mapper.Map<CustomerSource, CustomerTarget>(source);
Console.WriteLine(res1.FirstName); // PRINT FirstName
source.FirstName += "[UPDATED]";
source.LastName += "[UPDATED]";
var res2 = Mapper.Map<CustomerSource, CustomerTarget>(source);
Console.WriteLine(res1.FirstName); // PRINT FirstName[UPDATED]
}
Without your code, it is difficult to go more deeply. There is also a method Mapper.Reset() that clears the MapperEngine and the MapingConfiguration (all internal mapping expressions will be lost)
There is now an option to disable the cache.
Mapper.CreateMap<Tag, Tag>();
var results = Mapper.Map<IList<Tag>, IList<Tag>>(source, opt => opt.DisableCache = true);