Automapper: bidirectional mapping with ReverseMap() and ForMember()
Asked Answered
H

2

79

I have the case where I want to map an entity to a viewmodel and back. I have to specify the mapping explicitly with ForMember() because their properties do not share the exact same names. Here is a short example of how my classes look like:

public class PartTwo {
    public int Integer { get; set; }
}

public class PartTwoViewModel {
    public int PartInteger { get; set; }
}

And I want to use them this way:

Mapper.CreateMap<PartTwo, PartTwoViewModel>()
    .ForMember(dst => dst.PartInteger, opt => opt.MapFrom(src => src.Integer))
    .ReverseMap();

var partTwoViewModel = new PartTwoViewModel() { PartInteger = 42 };
var partTwo = Mapper.Map<PartTwoViewModel, PartTwo>(partTwoViewModel);
Assert.AreEqual(partTwoViewModel.PartInteger, partTwo.Integer);

But it does not match the property PartInteger to Integer. (Integer is 0.)

Is there a way to make this work? (When the properties of both classes have the same names it works.) Do I have to set some kind of option in the method ForMember()?

Hoot answered 21/11, 2012 at 9:49 Comment(1)
I just tried to use ReverseMap the way you did, and it works well. This question is outdated.Sternberg
O
58

You could define your configuration like this:

Mapper.CreateMap<PartTwo, PartTwoViewModel>()
    .ForMember(dst => dst.PartInteger, opt => opt.MapFrom(src => src.Integer));

Mapper.CreateMap<PartTwoViewModel, PartTwo>()
    .ForMember(dst => dst.Integer, opt => opt.MapFrom(src => src.PartInteger));

UPDATE

Here is the commit where ReverseMap was initially implemented. From what I can see in the code, it only creates a simple reverse mapping. For example, in this case it would automatically configure the equivalent of:

Mapper.CreateMap<PartTwoViewModel, PartTwo>();

To get anything more complex, I'm afraid that you're going to have to configure it manually.

Orlandoorlanta answered 21/11, 2012 at 10:30 Comment(2)
Yes this works. I hoped that I would not have to define the reverse mapping, because I have many properties which I map via ForMember().Hoot
One thing to note is that using ReverseMap with AssertConfigurationIsValid, is that the reverse side will not be validated. I have begun to prefer explicit maps for both sides to ensure that properties added to one side or the other don't get missed in validation.Lanai
T
169

ReverseMap returns an IMappingExpression that represents the reversal of the mapping. Once you call, it subsequent calls will be for configuring the reversal of the map.

Here's an example:

Mapper.CreateMap<CartItemDto, CartItemModel>()
      .ForMember(dest => dest.ExtendedCost, opt => opt.Ignore())
      .ReverseMap()
          .ForMember(dest => dest.Pricing, opt => opt.Ignore())

This will ignore the Pricing field in the reverse direction.

Touched answered 28/8, 2013 at 13:57 Comment(3)
Excellent. While it's still inconvenient to have to create the member mappings again, this is better than having to create an entirely new map.Cocytus
@jon Wingfield I appreciate your answer, but I am also a little confused. If I still have to re-do all of may .ForMember calls after I call ReverseMap, is it gaining me anything? Is it just a that .ignore is broken?Infusive
@Infusive It's been a while, but I don't think you need to redo all the ForMember calls, just anything that isn't already mapped.Touched
O
58

You could define your configuration like this:

Mapper.CreateMap<PartTwo, PartTwoViewModel>()
    .ForMember(dst => dst.PartInteger, opt => opt.MapFrom(src => src.Integer));

Mapper.CreateMap<PartTwoViewModel, PartTwo>()
    .ForMember(dst => dst.Integer, opt => opt.MapFrom(src => src.PartInteger));

UPDATE

Here is the commit where ReverseMap was initially implemented. From what I can see in the code, it only creates a simple reverse mapping. For example, in this case it would automatically configure the equivalent of:

Mapper.CreateMap<PartTwoViewModel, PartTwo>();

To get anything more complex, I'm afraid that you're going to have to configure it manually.

Orlandoorlanta answered 21/11, 2012 at 10:30 Comment(2)
Yes this works. I hoped that I would not have to define the reverse mapping, because I have many properties which I map via ForMember().Hoot
One thing to note is that using ReverseMap with AssertConfigurationIsValid, is that the reverse side will not be validated. I have begun to prefer explicit maps for both sides to ensure that properties added to one side or the other don't get missed in validation.Lanai

© 2022 - 2024 — McMap. All rights reserved.