Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapping collections inside objects

I am new to AutoMapper tool, which BTW is amazing so far. I am running into difficulties of mapping collections inside Model and corresponding ViewModel objects.

For simplicity, I have trimmed the code:

Model:

public class VoteQuestion
{        
    public virtual ICollection<VoteAnswerOption> VoteAnswerOptions { get; set; }
}

Corresponding ViewModel:

public class CreateVoteQuestionViewModel
{        
    public List<VoteAnswerOptionViewModel> PossibleAnswers { get; set; }
}

Another Model:

public class VoteAnswerOption
{
    public string Answer { get; set; }
}

And corresponding ViewModel:

public class VoteAnswerOptionViewModel
{
    public string Answer { get; set; }
}

My Mapper setup in 'Startup.cs'. Tried a few options, it worked for everything else except mapping collections.

        Mapper.Initialize(config =>
        {          
            config.CreateMap<VoteAnswerOption, VoteAnswerOptionViewModel>().ReverseMap();

            config.CreateMap<List<VoteAnswerOptionViewModel>, ICollection<VoteAnswerOption>>().ReverseMap();

            config.CreateMap<VoteQuestion, CreateVoteQuestionViewModel>()
            .ForMember(dest => dest.PossibleAnswers, opts => opts.MapFrom(src => src.VoteAnswerOptions))
            .ForMember(dest=>dest.PossibleAnswers,opts=>opts.MapFrom(src=>Mapper.Map<ICollection<VoteAnswerOption>, List<VoteAnswerOptionViewModel>>(src.VoteAnswerOptions)))
            .ReverseMap();
        });

And finally, the mapping in my Controller action:

var newQuestion = Mapper.Map<CreateVoteQuestionViewModel, VoteQuestion>(voteQuestion);

What am I missing?

like image 1000
lucas Avatar asked Jul 15 '26 09:07

lucas


1 Answers

This test passes: note that you can only use ReverseMap() when the mappings are simple and don't include any ForMember calls.

public class VoteQuestion {
    public virtual ICollection<VoteAnswerOption> VoteAnswerOptions { get; set; }
}


public class CreateVoteQuestionViewModel {
    public List<VoteAnswerOptionViewModel> PossibleAnswers { get; set; }
}


public class VoteAnswerOption {
    public string Answer { get; set; }
}


public class VoteAnswerOptionViewModel {
    public string Answer { get; set; }
}


[TestFixture]
public class SOTests {
    [Test]
    public void Test_41247396() {
        Mapper.Initialize(config => {
            config.CreateMap<VoteAnswerOption, VoteAnswerOptionViewModel>().ReverseMap();

            config.CreateMap<VoteQuestion, CreateVoteQuestionViewModel>()
                .ForMember(dest => dest.PossibleAnswers, 
                           opts => opts.MapFrom(src => src.VoteAnswerOptions));

            config.CreateMap<CreateVoteQuestionViewModel, VoteQuestion>()
                .ForMember(dest => dest.VoteAnswerOptions, 
                           opts => opts.MapFrom(src => src.PossibleAnswers));

        });

        var voteQuestion = new VoteQuestion {
            VoteAnswerOptions = new List<VoteAnswerOption> {
                new VoteAnswerOption { Answer = "Correct" }
            }
        };

        var newQuestion = Mapper.Map<VoteQuestion, CreateVoteQuestionViewModel>(voteQuestion);
        newQuestion.PossibleAnswers.Count.Should().Be(1);
        newQuestion.PossibleAnswers.Single().Answer.Should().Be("Correct");

        var vm = new CreateVoteQuestionViewModel {
            PossibleAnswers = new List<VoteAnswerOptionViewModel> {
                new VoteAnswerOptionViewModel {Answer = "Spot on"}
            }
        };

        var q = Mapper.Map<CreateVoteQuestionViewModel, VoteQuestion>(vm);
        q.VoteAnswerOptions.Count.Should().Be(1);
        q.VoteAnswerOptions.Single().Answer.Should().Be("Spot on");

    }
}
like image 157
stuartd Avatar answered Jul 17 '26 23:07

stuartd