t316
t316

Reputation: 1159

Automapper Composite DTO to ViewModel conversion

In some cases there is a need to return composite DTOs from our repository, where the DTO just has a few properties that are Model properties and the function of the DTO is just to be a simple composite object (returning a Queryable is not enough because there is more information than T)

For example:

Model:

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

Now - Id like to simply do (Project and To are Automapper functionality):

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

So I need a mapping kind of like this:

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

I am attempting to map the Job property of the DTO directly on to the JobVM (which shares many of the same properties).

My mapping throws the following exception:

Custom configuration for members is only supported for top-level individual members on a type.

What am I doing wrong and how can I accomplish the mapping form the Job property of the DTO on the the JobVM itself?

Thanks

Upvotes: 0

Views: 3932

Answers (1)

Jason More
Jason More

Reputation: 7073

Automapper is telling you that you can only define custom actions on a member (property) of a class, not on the class itself. What you need to do is first create a Job to JobVM map:

Mapper.CreateMap<Job, JobVM>()

and

Mapper.CreateMap<JobAndUserApplication, JobVM>()

being sure to ignore and set any duplicate properties across the two types. Then run automapper twice, first from the child object:

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

then from the parent object

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

Or the other way around, depending on how your properties are laid out.

Quick side note: I have a feeling you might be mixing concerns, and my code smell alarm is going off. I'd take a second look at either your viewmodel or domain model, as this is not a typical issue I see come up. (just my $0.02 :-)

Upvotes: 1

Related Questions