AutoMapper TwoWay Mapping with the same property name

Given these two objects

public class UserModel
{
    public string Name {get;set;}
    public IList<RoleModel> Roles {get;set;}
}

public class UserViewModel 
{
    public string Name {get;set;}
    public IList<RoleViewModel> Roles {get;set;} // notice the ViewModel
}

      

Is this the most optimal way to do the mapping or is AutoMapper able to map Roles

in on Roles

its own?

App Config

Mapper.CreateMap<UserModel, UserViewModel>()
    .ForMember(dest => dest.Roles, opt => opt.MapFrom(src => src.Roles));
Mapper.CreateMap<UserViewModel, UserModel>()
    .ForMember(dest => dest.Roles, opt => opt.MapFrom(src => src.Roles));

      

Implementation

_userRepository.Create(Mapper.Map<UserModel>(someUserViewModelWithRolesAttached);

      

+3


source to share


4 answers


Is this the most optimal way to do the mapping, or is AutoMapper capable of mapping Roles to Roles on its own?

If the property names are identical, you don't need to manually specify the mapping:

Mapper.CreateMap<UserModel, UserViewModel>();
Mapper.CreateMap<UserViewModel, UserModel>();

      



Just make sure the inner types are shown as well ( RoleViewModel

โ†” RoleModel

)

However, this means that if you change the name of the source or destination property, the AutoMapper mappings can fail and cause troubleshooting problems (for example, if you changed UserModel.Roles

to UserModel.RolesCollection

no change UserViewModels.Roles

).

AutoMapper provides a method Mapper.AssertConfigurationIsValid()

that will check all of your mappings for errors and display misconfigured mappings. It's helpful to have a unit test that works with an assembly that checks your mappings for this problem.

+6


source


You don't need to display properties. Just make sure the property names match and a mapping is defined between them.

Mapper.CreateMap<UserModel, UserViewModel>();
Mapper.CreateMap<UserViewModel, UserModel>();
Mapper.CreateMap<RoleModel, RoleViewModel>();
Mapper.CreateMap<RoleViewModel, RoleModel>();

      



Or with a colder way I just found out:

Mapper.CreateMap<UserModel, UserViewModel>().ReverseMap();
Mapper.CreateMap<RoleModel, RoleViewModel>().ReverseMap();

      

+11


source


All other answers are much better (which I gave to each one).

But what I wanted to post here is a quick playground that you could copy and run right into LinqPad in C # program mode and play your idea without messing around with your actual code.

Another awesome thing about bringing all your conversions into the TyperConverter class is that your conversions are now Unit Testable. :)

Here you will notice that the model and viewmodel are almost identical except for one property. But through this process, the legal property is converted to the correct property in the target.

Copy this code into LinqPad and you can run it with play button after entering C # programming mode.

void Main()
{
    AutoMapper.Mapper.CreateMap<UserModel, UserViewModel>().ConvertUsing(new UserModelToUserViewModelConverter());
    AutoMapper.Mapper.AssertConfigurationIsValid();

    var userModel = new UserModel
    {
        DifferentPropertyName = "Batman",
        Name = "RockStar",
        Roles = new[] {new RoleModel(), new RoleModel() }
    };

    var userViewModel = AutoMapper.Mapper.Map<UserViewModel>(userModel);
    Console.WriteLine(userViewModel.ToString());
}

// Define other methods and classes here
public class UserModel
{
    public string Name {get;set;}
    public IEnumerable<RoleModel> Roles { get; set; }
    public string DifferentPropertyName { get; set; }
}

public class UserViewModel 
{
    public string Name {get;set;}
    public IEnumerable<RoleModel> Roles { get; set; } // notice the ViewModel
    public string Thingy { get; set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(string.Format("Name: {0}", Name));
        sb.AppendLine(string.Format("Thingy: {0}", Thingy));
        sb.AppendLine(string.Format("Contains #{0} of roles", Roles.Count()));

        return sb.ToString();
    }
}

public class UserModelToUserViewModelConverter : TypeConverter<UserModel, UserViewModel>
{
    protected override UserViewModel ConvertCore(UserModel source)
    {
        if(source == null)
        {
            return null;
        }

        //You can add logic here to deal with nulls, empty strings, empty objects etc
        var userViewModel = new UserViewModel
        {
             Name = source.Name,
             Roles = source.Roles, 
             Thingy = source.DifferentPropertyName
        };
        return userViewModel;
    }
}

public class RoleModel
{
    //no content for ease, plus this has it own mapper in real life
}

      

Result from Console.WriteLine(userViewModel.ToString());

:

Name: RockStar
Thingy: Batman
Contains #2 of roles

      

0


source


Inside Startup.cs in Configure () method:

Mapper.Initialize(config => {
                    config.CreateMap<UserModel, UserViewModel>().ReverseMap();
                    // other maps you want to do.
                });

      

0


source







All Articles