IncludeMembers() will always map from first match even if object is null.
Let's say we have the following source models:
public class Item
{
public MovieMetadata MovieMetadata { get; set; }
public BookMetadata BookMetadata { get; set; }
}
public class MovieMetadata
{
public string Title { get; set; }
}
public class BookMetadata
{
public string Title { get; set; }
}
Destination model:
public class ItemDetail
{
public string Title { get; set; }
}
Mapping profile:
public class ItemProfile : Profile
{
public ItemProfile()
{
CreateMap<Item, ItemDetail>()
.IncludeMembers(
src => src.BookMetadata,
src => src.MovieMetadata);
CreateMap<BookMetadata, ItemDetail>();
CreateMap<MovieMetadata, ItemDetail>();
}
}
And Program class with instantiation and testing logic:
public class Program
{
public static void Main()
{
//create mapper
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(ItemProfile));
});
var mapper = configuration.CreateMapper();
//check if configuration valid
mapper.ConfigurationProvider.AssertConfigurationIsValid();
Console.WriteLine("Mapper configuration is valid");
//try map book metadata
var bookItem = new Item
{
BookMetadata = new BookMetadata()
{
Title = "book"
},
MovieMetadata = null
};
var bookItemDetail = mapper.Map<ItemDetail>(bookItem);
bool isBookCorrectlyMapped = bookItem.BookMetadata.Title == bookItemDetail.Title;
Console.WriteLine($"Book mapped correctly: {isBookCorrectlyMapped}");
//try map movie metadata
var movieItem = new Item
{
BookMetadata = null,
MovieMetadata = new MovieMetadata()
{
Title = "movie"
}
};
var movieItemDetail = mapper.Map<ItemDetail>(movieItem);
bool isMovieCorrectlyMapped = movieItem.MovieMetadata.Title == movieItemDetail.Title;
Console.WriteLine($"Movie mapped correctly: {isMovieCorrectlyMapped}");
}
}
This is the output we will see:
Mapper configuration is valid
Book mapped correctly: True
Movie mapped correctly: False
We see that mapping for item with BookMetadata succeeded, but for MovieMetadata failed. Need to make updates so this test succeeds.
Suppose the reason it's failing is because of order of items in IncludeMembers():
.IncludeMembers(
src => src.BookMetadata,
src => src.MovieMetadata)
Here we have src.BookMetadata first and src.MovieMetadata second. During mapping it will find Title field in src.BookMetadata and will always use this value even if src.BookMetadata is null.
Is there any way to skip src.BookMetadata if it is null and use next src.MovieMetadata instead? Or probably need to use something else instead of IncludeMembers()?
Here is similar issue: https://github.com/AutoMapper/AutoMapper/issues/3204
Code above you can find here to quickly reproduce issue: https://dotnetfiddle.net/9YLGR6