2014-01-28 2 views
34

Скажем, у меня есть две модели классов:AutoMapper конвертировать из нескольких источников

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

также класс Телефон:

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

И я хочу, чтобы преобразовать в PeoplePhoneDto так:

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

Скажем, в моем контроллере у меня есть:

var people = repository.GetPeople(1); 
var phone = repository.GetPhone(4); 

// normally, without automapper I would made 
return new PeoplePhoneDto(people, phone) ; 

Я не могу найти ни одного примера для этого сценария. Это возможно ?

Примечание: пример не является реальным, только для этого вопроса.

+0

@Andrei в то время как я согласен, кажется, похоже, разница в задаче он пытается решать.также трудно понять из этого вопроса, как это применимо к этому. –

+0

Почему бы не сделать 'PeoplePhoneDto' членом' People' и 'Phone'? – crush

+0

Потому что это не то, что я хочу разоблачить. –

ответ

56

Вы не можете непосредственно на карте много источников в одно место назначения - вы должны применять карты один на один, как описано в Andrew Whitaker ответ. Таким образом, вы должны определить все отображения:

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

Затем создать объект назначения с помощью любого из этих отображений, а также применять другие отображения на созданный объект. И этот шаг может быть упрощен с очень простым методом расширения:

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

Использования очень просто:

var dto = Mapper.Map<PeoplePhoneDto>(people) 
       .Map(phone); 
+1

именно то, что я искал! Спасибо ! –

+0

В AutoMapper имеется абстракция [IMapper] (https://gist.github.com/ilyapalkin/8822638) для сопоставления нескольких источников в один пункт назначения, который я использую. –

+0

@Sergey Berezovskiy, я создал сопоставления, добавил метод расширения в класс PeoplePhoneDto и скопировал ваше использование (Т.е., я скопировал все необходимое), но я получаю ошибку «Нет перегрузки для метода Map принимает один аргумент» , Что мне не хватает? Я использую Automapper 4.2.1. – HeyJude

8

Вы можете использовать Tuple для этого:

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)); 

В случае, если будет иметь больше моделей источников, которые можно использовать другое представление (List, словарь или что-то еще), собирающие все эти модели вместе, как источник.

Приведенный выше код должен быть помещен в некоторый файл AutoMapperConfiguration, установленный один раз и глобально, а затем используемый, когда это применимо.

AutoMapper по умолчанию поддерживает только один источник данных. Таким образом, нет возможности устанавливать сразу несколько источников (без их обертывания в коллекции), потому что тогда как мы узнаем, что, если, например, у двух исходных моделей есть свойства с одинаковыми именами?

Существует хотя некоторые обходной путь для достижения этой цели:

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; 
    } 
} 

А потом:

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

Но чтобы быть совсем честным, даже если я использую AutoMapper для уже несколько лет я никогда необходимо было использовать сопоставление из нескольких источников. В тех случаях, когда, например, мне понадобилось несколько бизнес-моделей в моей модели с одним представлением, я просто встроил эти модели в класс модели представления.

Так что в вашем случае это будет выглядеть следующим образом:

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

Так что я должен создать кортеж, прежде чем делать сопоставление, мне интересно, какие реальные преимущества automapper ... звук немного перебор. Есть ли способ избежать создания другого типа (кортеж, dic и т. Д.)? –

+0

спасибо за ваш ответ, это заставляет меня много разбираться в automapper. Дело в том, что когда вы открываете API, вы тщательно моделируете данные способами, которые иногда имеют встроенные модели, не желательны, потому что вы переносите свои «связанные с доменом» проблемы для потребителя, и я стараюсь, чтобы клиенты могли потреблять без вложенных типов , Если бы это было для моего внутреннего использования, я обязательно перейду с встроенным опцией. –

+1

«PeoplePhoneDto», который вы предлагаете, выглядит хорошо, но я все же думаю, что отображение из нескольких источников полезно, особенно в картографических моделях. Я думаю, что для большинства сценариев реального мира требуется несколько источников для создания модели представления. Я полагаю, вы могли бы создать модели просмотра, которые не сглажены, чтобы обойти эту проблему, но я думаю, что неплохо создать модели представления, не заботясь о том, как выглядит бизнес-схема. –

Смежные вопросы