Introduction
I have an ASP.NET Core MVC Web Applications with models and view models fitting the architecture of the database and fields required in each view. I choose Automapper to simplify the conversion between the object from the database and to the view. In some cases, the conversion is one to one, in others, one view models should be converted to many domain models.
Background
This link explains how to get started with Automapper in .NET Core. Also, here you can read about creating maps for different scenarios. Additionally, there are many comments on Stackoverflow about using tuples to create one to many classes maps.
Using the Code
First, you can create a map for a conversion from one domain model to one view model as follows:
CreateMap<ViewModels.Base, Models.Base>()
.ForMember(dest => dest.BaseId, opts => opts.MapFrom(src => src.BaseId))
.ForMember(dest => dest.UserId, opts => opts.MapFrom(src => src.UserId))
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name));
CreateMap<ViewModels.Base, Models.Base>().ReverseMap();
If field names do not match, you need to specify them. You can define the reverse map.
On the other hand, for the case where a view model should be mapped with two domain models, you can use tuples as the following example.
CreateMap<System.Tuple<Models.Base, Models.BaseStatus>, ViewModels.Base>()
.ForMember(dest => dest.BaseId, opts => opts.MapFrom(src => src.Item1.BaseId))
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Item1.Name))
.ForMember(dest => dest.UserId, opts => opts.MapFrom(src => src.Item1.UserId))
.ForMember(dest => dest.IsConnected, opts => opts.MapFrom(src => src.Item2.IsConnected))
.ForMember(dest => dest.IsPlugged, opts => opts.MapFrom(src => src.Item2.IsPlugged));
For the reverse map, you will in each case pick the fields corresponding to each class:
CreateMap<ViewModels.Base, Models.Base>()
.ForMember(dest => dest.BaseId, opts => opts.MapFrom(src => src.BaseId))
.ForMember(dest => dest.UserId, opts => opts.MapFrom(src => src.UserId))
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name));
CreateMap<ViewModels.Base, Models.BaseStatus>()
.ForMember(dest => dest.BaseId, opts => opts.MapFrom(src => src.BaseId))
.ForMember(dest => dest.IsConnected, opts => opts.MapFrom(src => src.IsConnected))
.ForMember(dest => dest.IsPlugged, opts => opts.MapFrom(src => src.IsPlugged));
Another option, for the one to many mappings could be using class composition. As soon as Models.Base
and ViewModels.Base
contains a field that is the Models.BaseStatus
.
CreateMap<Models.Base, ViewModels.Base>()
.ForMember(dest => dest.BaseId, opts => opts.MapFrom(src => src.BaseId))
.ForMember(dest => dest.Name, opts => opts.MapFrom(src => src.Name))
.ForMember(dest => dest.UserId, opts => opts.MapFrom(src => src.UserId))
.ForMember(dest => dest.Status, opts => opts.MapFrom(src => new BaseStatus
{
IsConnected = src.IsConnected,
IsPlugged = src.IsPlugged))
};
Finally, this is the way the maps can be called:
ViewModels.Base vmb = _mapper.Map<BaseViewModel>(new Tuple<Models.Base, Models.BaseStatus>(b, bs));
ViewModels.Base vmb = _mapper.Map<Models.Base>(b);