2012-04-30 2 views
0

В некоторых случаях необходимо возвращать составные DTO из нашего репозитория, где DTO имеет только несколько свойств, которые являются свойствами модели, а функция DTO - просто простой составной объект (возвращающая Queryable не хватает, потому что есть больше информации, чем T)Automapper Composite DTO to ViewModel conversion

Например:

Модель:

public class Job 
{ 
    int Id { get; set; } 
    //more properties 
} 

public class JobApplication 
{ 
    int Id { get; set; } 
    //more properties 
} 

Repository: IQueryable<JobAndUserApplication> GetJobAndMatchingUserApplication(int userId):

public class JobAndUserApplication 
{ 
    public Job Job { get; set; } 
    public JobApplication JobApplication { get; set; } 
} 

Теперь - Id как просто сделать (Project и К являются функциональность Automapper):

//this allows one efficient query to bring in the subproperties of the composite DTO  
var jobVmList = jobRepository.GetAllJobsAndMatchingJobApplicationByUser(userId)    
          .Project() 
          .To<JobVM>() 
          .ToList(); 

Так что мне нужно отображение вроде как это:

Mapper.CreateMap<JobAndUserApplication, JobVM>() 
     .ForMember(jvm => jvm, opt => opt.ResolveUsing(src => src.Job)); 
     //many other .ForMembers that are not relevant right now 

Я пытаю для сопоставления свойства Job DTO непосредственно на JobVM (который разделяет многие из тех же свойств).

Мой картирование бросает следующее исключение:

Пользовательские настройки для членов поддерживается только для верхнего уровня отдельных членов по типу.

Что я делаю неправильно и как я могу выполнить сопоставление, используя свойство Job DTO на самом JobVM?

Благодаря

ответ

1

Automapper говорит вам, что вы можете только собственные действия на члене (собственность) класса, а не на самом классе. Что вам нужно сделать, это создать первую работу на карте JobVM:

Mapper.CreateMap<Job, JobVM>() 

и

Mapper.CreateMap<JobAndUserApplication, JobVM>() 

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

var jobVM = Mapper.Map<Job, JobVM>(jobAndUserApplication.job); 

затем из родительского объекта

Mapper.Map<JobAndUserApplication, JobVM>(jobAndUserApplication, jobVM); 

Или наоборот, в зависимости от того, как свойства раскладывают.

Быстрое примечание: у меня есть чувство, что вы можете смешивать проблемы, и мой сигнал от запаха кода уходит. Я бы взглянул на модель вашего модели или модель домена, поскольку это не типичная проблема, которую я вижу. (только мои $ 0.02 :-)

+0

Спасибо Джейсону. Я пытался избежать вызова метода Map дважды - не то, что это огромная сделка, но я думал, что AutoMapper с его богатой конфигурацией, несомненно, сможет позволить мне настроить сопоставление, так что мне нужно только один раз вызвать карту. Я отвечу на запах кода в другом комментарии. – t316

+0

Наши репозитории возвращаются. Модели и наши сервисные слои работают с репозиториями и возвращают DTO.Вызов нескольких методов репозитория в службах для склеивания полученных результатов - это ненужная проблема с производительностью (несколько запросов и ненужная обработка в памяти, которая хорошо работает с базой данных). Другого способа я не знаю, кроме использования составного класса (который просто склеивает две Модели вместе), чтобы возвращать Модели для запуска одного эффективного выбора запроса, который не нужно делать при обработке памяти. Это связано с тем, что AFAIK Automapper не может обрабатывать анонимные типы. – t316

+0

А это имеет смысл. Другой подход, который вы можете предпринять, заключается в настройке настраиваемой логики сопоставления .AfterMap() Вы используете анонимные функции для определения настраиваемой логики сопоставления, которая может помочь вам избежать второго вызова. –