Sarfaraz Jamal
Sarfaraz Jamal

Reputation: 403

Convert Simple DTP into Complex DTO using AutoMapper

I have a simple DTO that looks like this:

    public partial class Company
    {
        public string NAME { get; set; }        

        public string CONTACT_ADDR1_1 { get; set; }
        public string CONTACT_ADDR2_1 { get; set; }
        public string CONTACT_CITY_1 { get; set; }
        public string CONTACT_STATE_1 { get; set; }
        public string CONTACT_ZIP_1 { get; set; }

        public string CONTACT_ADDR1_2 { get; set; }
        public string CONTACT_ADDR2_2 { get; set; }
        public string CONTACT_CITY_2 { get; set; }
        public string CONTACT_STATE_2 { get; set; }
        public string CONTACT_ZIP_2 { get; set; }

        public string CONTACT_ADDR1_3 { get; set; }
        public string CONTACT_ADDR2_3 { get; set; }
        public string CONTACT_CITY_3 { get; set; }
        public string CONTACT_STATE_3 { get; set; }
        public string CONTACT_ZIP_3 { get; set; }
     }

And I want to use AutoMapper to convert it into a Company object with a List of Type. I will have a KNOWN number of addresses (6). I have only listed three however.

    public partial class CompanyDto
    {
        public string NAME { get; set; }
        public List<AddressDto> { get; set; }
     }

    public partial class AddressDto
    {
        public string CONTACT_ADDR1 { get; set; }
        public string CONTACT_ADDR2 { get; set; }
        public string CONTACT_CITY { get; set; }
        public string CONTACT_STATE { get; set; }
        public string CONTACT_ZIP { get; set; }
     }

This is the block of code I am having difficulty with:

cfg.CreateMap<Company, CompanyDto>();

Upvotes: 2

Views: 160

Answers (3)

Renat
Renat

Reputation: 9002

I would prefer @Train 's answer, as much more comprehensible approach, which is also much easier to debug and troubleshoot.

But if AutoMapper is mandatory, you may use a Custom Value Resolver, e.g. like:

public class CompanyToCompanyDtoResolver : IValueResolver<Company, CompanyDto, List<AddressDto>>
{            
    public List<AddressDto> Resolve(Company source, CompanyDto destination, List<AddressDto> destMember, ResolutionContext context)
    {
        var contacts = new List<AddressDto>();

        var companyType = typeof(Company);

        for (int i = 1; i <= 6; i++)
        {
            var address = new AddressDto();

            address.CONTACT_ADDR1 = (string)companyType
                .GetProperty(nameof(Company.CONTACT_ADDR1_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_ADDR2 = (string)companyType
                .GetProperty(nameof(Company.CONTACT_ADDR2_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_CITY = (string)companyType
                .GetProperty(nameof(Company.CONTACT_CITY_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_STATE = (string)companyType
                .GetProperty(nameof(Company.CONTACT_STATE_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            address.CONTACT_ZIP = (string)companyType
                .GetProperty(nameof(Company.CONTACT_ZIP_1).Replace("_1", $"_{i}"))
                .GetValue(source);

            contacts.Add(address);
        }

        return contacts;
    }
}

...

    cfg.CreateMap<Company, CompanyDto>()
       .ForMember(destination => destination.Contacts, 
                  source => source.MapFrom<CompanyToCompanyDtoResolver>());

Upvotes: 1

Callum Goodridge
Callum Goodridge

Reputation: 41

        CreateMap<Company, CompanyDto>()
            .AfterMap((s, d) =>
            {
                d.ADDRESSES = new System.Collections.Generic.List<AddressDto>();
                d.ADDRESSES.Add(new AddressDto
                {
                    CONTACT_ADDR1 = s.CONTACT_ADDR1_1,
                    CONTACT_ADDR2 = s.CONTACT_ADDR1_2,
                    CONTACT_CITY = s.CONTACT_CITY_1,
                    CONTACT_STATE = s.CONTACT_STATE_1,
                    CONTACT_ZIP = s.CONTACT_ZIP_1
                });
                d.ADDRESSES.Add(new AddressDto
                {
                    CONTACT_ADDR1 = s.CONTACT_ADDR2_1,
                    CONTACT_ADDR2 = s.CONTACT_ADDR2_2,
                    CONTACT_CITY = s.CONTACT_CITY_2,
                    CONTACT_STATE = s.CONTACT_STATE_2,
                    CONTACT_ZIP = s.CONTACT_ZIP_2
                });
            });

The above may work (and repeat for the number of addresses you have). I must admit I haven't actually run this code but it looks passable

Upvotes: 3

Train
Train

Reputation: 3506

I wouldn't suggest using automapper for this.

Took me 2 minutes to type this up, it won't take you more than 10 minutes to do this. I would suggest creating extension methods and converting your own DTO's for complex mappings. It would save you plenty of headache trying to configure it through a third party library.

public static class CompanyExtensions{

   public static CompanyDto ToCompanyDto(this Company c){

     var cDto = new CompanyDto();

     cDto.Name = c.Name;
     cDto.Addresses = new List<AddressDto>();
     cDto.Addresses.Add(c.ToAddress1Dto());
     cDto.Addresses.Add(c.ToAddress2Dto());
     ...
     return cDto;


   }

  public static AddressDto ToCopmanyAddress1Dto(this Company c){
    return new AddressDto()
     {
      CONTACT_ADDR1 = c.CONTACT_ADDR1,
      CONTACT_ADDR2 = c.CONTACT_ADDR2,
      CONTACT_CITY = c.CONTACT_CITY,
      CONTACT_STATE = c.CONTACT_STATE,
      CONTACT_ZIP = c.CONTACT_ZIP 
     }
  }

 public static AddressDto ToCopmanyAddress2Dto(this Company c){
  ...
 }

 ... for the other addresses
}

Upvotes: 3

Related Questions