AutoMapping two objects based on condition

Trying to figure if it is possible in AutoMapper to map Customer and Address model's into a list of CustomerDetails where the ID value in Customer matches the CustomerID in Address?

public class Customer {
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

public class Address {
    public int ID { get; set;}
    public int CustomerID { get; set; }
    public string Address1 { get; set; }
    public string Address2  { get; set; }
    public string Town { get; set; }
    public string PostCode { get; set; }
}

public class CustomerDetails{
    public int ID { get; set; }
    public Customer CustomerInfo { get; set; }
    public Address CustomerAddress { get; set; }
}

The end goal is to have the following Json Object

{
  ID: 1234,  
  CustomerInfo: {
      ID: 1,
      FirstName: "John",
      Surname: "Connor"   
  }
  CustomerAddress: {
      ID: 1232,
      CustomerID: 1,
      Address1: "123 Avenue",
      Address2: "Some road",
      Town: "London",
      PostCode: "L1WLL"
  }  
}

So far I can only think of following AutoMapper configuration

Mapper.CreateMap<Customer, CustomerDetails>();
Mapper.CreateMap<Address, CustomerDetails>()

Usage

var mapping = Mapper.Map<CustomerDetails>(Customer)
                .Map(Address);

1 answer

  • answered 2020-01-14 03:27 Dinand Lybaert

    You could combine the 2 collections into a tuple type (Customer, Address) based on the customer id and map that type to the CustomerDetail type.

    CreateMap<(CustomerDetails cust, Address addr), CustomerDetails>();
    customers.Select(r => (r, addresses.FirstOrDefault(a => a.CustomerID == r.ID))).Select(g => mapper.Map(g));
    

    You can also map in 2 stages, first map the customers to customer details and then map addresses to customer details:

            CreateMap<Customer, CustomerDetails>()
                .ForMember(d => d.ID, opt => opt.MapFrom(s => s.ID))
                .ForMember(d => d.CustomerInfo, opt => opt.MapFrom(s => s))
                .ForAllOtherMembers(opt => opt.Ignore());
    
            CreateMap<Address, CustomerDetails>()
                .ForMember(d => d.CustomerAddress, opt => opt.MapFrom((s, d) => d.ID == s.CustomerID ? s : d.CustomerAddress))
                .ForAllOtherMembers(opt => opt.Ignore());
    
            CreateMap<Address, IEnumerable<CustomerDetails>>()
                .ConvertUsing((a, d, ctx) =>
                {
                    CustomerDetails match = d.FirstOrDefault(c => c.ID == a.CustomerID);
                    if (match != null) 
                    {
                        ctx.Mapper.Map(match, a);
                    }
    
                    return d;
                });
    

    Mapping:

    List<Customer> customers = new List<Customer>();
    List<Address> addresses = new List<Address>();
    var result = mapper.Map<List<CustomerDetails>>(customers);
    addresses.ForEach(a => mapper.Map(a, result));