I've got a problem doing third level mapping. The classes are below:
public class Company {
public Contact MainContact { get; private set; }
}
public class Contact {
public PersonsName ContactName { get; private set; }
}
public class PersonsName {
public String FirstName { get; private set; }
public String LastName { get; private set; }
}
public class CreateCompanyViewModel {
[Required]
[MaxLength(25, ErrorMessage = "Only 25 characters are allowed.")]
[Display(Name = "First Name")]
public String FirstName { get; set; }
[Required]
[MaxLength(25, ErrorMessage = "Only 25 characters are allowed.")]
[Display(Name = "Last Name")]
public String LastName { get; set; }
}
I've tried the following with no success:
Mapper.CreateMap<CreateCompanyViewModel, PersonsName>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName));
Mapper.CreateMap<Contact, PersonsName>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.ContactName.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.ContactName.LastName));
Mapper.CreateMap<CreateCompanyViewModel, Company>()
.ForMember(dest => dest.MainContact.ContactName.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.MainContact.ContactName.FirstName, opt => opt.MapFrom(src => src.LastName));
The error message I get is:
Expression 'dest => dest.MainContact.ContactName.FirstName' must resolve to top-level member and not any child object's properties. Use a custom resolver on the child type or the AfterMap option instead. Parameter name: lambdaExpression
You can use the following configuration:
/* Innermost mapping */
Mapper.CreateMap<CreateCompanyViewModel, PersonsName>();
// You don't need the individual member mappings since the names match.
/* Second-level */
Mapper.CreateMap<CreateCompanyViewModel, Contact>()
.ForMember(dest => dest.ContactName, opt => opt.MapFrom(src => src));
/* Top level */
Mapper.CreateMap<CreateCompanyViewModel, Company>()
.ForMember(dest => dest.MainContact, opt => opt.MapFrom(src => src));
The idea is that you use the source type (CreateCompanyViewModel) as the source for the nested types as well. You accomplish this using the MapFrom(src => src) call inside of ForMember.
Example: https://dotnetfiddle.net/XBJMba
Since the src => src bit looks a little odd, you could create an extension method that makes what you're doing more straightforward:
public static class AutoMapperExtensions
{
public static void MapFromSelf<TSourceType>(
this IMemberConfigurationExpression<TSourceType> expression)
{
expression.MapFrom(s => s);
}
}
Usage:
Mapper.CreateMap<CreateCompanyViewModel, Contact>()
.ForMember(dest => dest.ContactName, opt => opt.MapFromSelf());
Mapper.CreateMap<CreateCompanyViewModel, Company>()
.ForMember(dest => dest.MainContact, opt => opt.MapFromSelf());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With