Let's say I have two model classes:
public class People { public string FirstName {get;set;} public string LastName {get;set;} }
Also have a class Phone:
public class Phone { public string Number {get;set;} }
And I want to convert to a PeoplePhoneDto like this:
public class PeoplePhoneDto { public string FirstName {get;set;} public string LastName {get;set;} public string PhoneNumber {get;set;} }
Let's say in my controller I have:
var people = repository.GetPeople(1); var phone = repository.GetPhone(4); // normally, without automapper I would made return new PeoplePhoneDto(people, phone) ;
I cannot seem to find any example for this scenario. Is this possible ?
Note: Example is not-real, just for this question.
You cannot directly map many sources to single destination - you should apply maps one by one, as described in Andrew Whitaker answer. So, you have to define all mappings:
Mapper.CreateMap<People, PeoplePhoneDto>(); Mapper.CreateMap<Phone, PeoplePhoneDto>() .ForMember(d => d.PhoneNumber, a => a.MapFrom(s => s.Number));
Then create destination object by any of these mappings, and apply other mappings to created object. And this step can be simplified with very simple extension method:
public static TDestination Map<TSource, TDestination>( this TDestination destination, TSource source) { return Mapper.Map(source, destination); }
Usage is very simple:
var dto = Mapper.Map<PeoplePhoneDto>(people) .Map(phone);
You could use a Tuple for this:
Mapper.CreateMap<Tuple<People, Phone>, PeoplePhoneDto>() .ForMember(d => d.FirstName, opt => opt.MapFrom(s => s.Item1.FirstName)) .ForMember(d => d.LastName, opt => opt.MapFrom(s => s.Item1.LastName)) .ForMember(d => d.Number, opt => opt.MapFrom(s => s.Item2.Number ));
In case you would have more source models you can use a different representation (List, Dictionary or something else) that will gather all these models together as a source.
The above code should preferaby be placed in some AutoMapperConfiguration file, set once and globally and then used when applicable.
AutoMapper by default supports only a single data source. So there is no possibility to set directly multiple sources (without wrapping it up in a collection) because then how would we know what in case if for example two source models have properties with the same names?
There is though some workaround to achieve this:
public static class EntityMapper { public static T Map<T>(params object[] sources) where T : class { if (!sources.Any()) { return default(T); } var initialSource = sources[0]; var mappingResult = Map<T>(initialSource); // Now map the remaining source objects if (sources.Count() > 1) { Map(mappingResult, sources.Skip(1).ToArray()); } return mappingResult; } private static void Map(object destination, params object[] sources) { if (!sources.Any()) { return; } var destinationType = destination.GetType(); foreach (var source in sources) { var sourceType = source.GetType(); Mapper.Map(source, destination, sourceType, destinationType); } } private static T Map<T>(object source) where T : class { var destinationType = typeof(T); var sourceType = source.GetType(); var mappingResult = Mapper.Map(source, sourceType, destinationType); return mappingResult as T; } }
And then:
var peoplePhoneDto = EntityMapper.Map<PeoplePhoneDto>(people, phone);
But to be quite honest, even though I am using AutoMapper for already a few years I have never had a need to use mapping from multiple sources. In cases when for example I needed multiple business models in my single view model I simply embedded these models within the view model class.
So in your case it would look like this:
public class PeoplePhoneDto { public People People { get; set; } public Phone Phone { get; set; } }