AutoMapper convertir à partir de plusieurs sources

Disons que j’ai deux classes de modèles:

public class People { public ssortingng FirstName {get;set;} public ssortingng LastName {get;set;} } 

Avoir aussi un téléphone de classe:

 public class Phone { public ssortingng Number {get;set;} } 

Et je veux convertir en un PeoplePhoneDto comme ceci:

 public class PeoplePhoneDto { public ssortingng FirstName {get;set;} public ssortingng LastName {get;set;} public ssortingng PhoneNumber {get;set;} } 

Disons que dans mon contrôleur j’ai:

 var people = repository.GetPeople(1); var phone = repository.GetPhone(4); // normally, without automapper I would made return new PeoplePhoneDto(people, phone) ; 

Je n’arrive pas à trouver d’exemple pour ce scénario. Est-ce possible ?

Note: L’exemple n’est pas réel, juste pour cette question.

Vous ne pouvez pas associer directement plusieurs sources à une seule destination – vous devez appliquer les cartes une par une, comme indiqué dans la réponse d’ Andrew Whitaker . Donc, vous devez définir tous les mappages:

 Mapper.CreateMap(); Mapper.CreateMap() .ForMember(d => d.PhoneNumber, a => a.MapFrom(s => s.Number)); 

Créez ensuite un object de destination par l’un de ces mappages et appliquez d’autres mappages à l’object créé. Et cette étape peut être simplifiée avec une méthode d’extension très simple:

 public static TDestination Map( this TDestination destination, TSource source) { return Mapper.Map(source, destination); } 

L’utilisation est très simple:

 var dto = Mapper.Map(people) .Map(phone); 

Vous pourriez utiliser un Tuple pour cela:

 Mapper.CreateMap, 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 )); 

Dans le cas où vous auriez plus de modèles sources, vous pouvez utiliser une représentation différente (Liste, Dictionnaire ou autre) qui rassemblera tous ces modèles en tant que source.

Le code ci-dessus devrait être placé dans un fichier AutoMapperConfiguration, défini une fois et globalement, puis utilisé le cas échéant.

AutoMapper par défaut ne prend en charge qu’une seule source de données. Il n’y a donc pas de possibilité de définir directement plusieurs sources (sans les envelopper dans une collection) car alors comment saurions-nous si, par exemple, deux modèles sources ont des propriétés avec les mêmes noms?

Il existe cependant une solution pour y parvenir:

 public static class EntityMapper { public static T Map(params object[] sources) where T : class { if (!sources.Any()) { return default(T); } var initialSource = sources[0]; var mappingResult = Map(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(object source) where T : class { var destinationType = typeof(T); var sourceType = source.GetType(); var mappingResult = Mapper.Map(source, sourceType, destinationType); return mappingResult as T; } } 

Et alors:

 var peoplePhoneDto = EntityMapper.Map(people, phone); 

Mais pour être tout à fait honnête, même si j’utilise AutoMapper depuis déjà quelques années, je n’ai jamais eu besoin d’utiliser le mapping de plusieurs sources. Dans les cas où, par exemple, j’avais besoin de plusieurs modèles d’entreprise dans mon modèle à vue unique, j’ai simplement intégré ces modèles dans la classe du modèle de vue.

Donc, dans votre cas, cela ressemblerait à ceci:

 public class PeoplePhoneDto { public People People { get; set; } public Phone Phone { get; set; } }