AutoMapper - Map list of flat objects to complex object

53 Views Asked by At

I'm using AutoMapper in a .NET 6 application to map multiple records from a source list to a list property in the destination object.

Source Object:

public class UserDetailDto
{
    public string ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
}

Destination Object:

public class UserDetail
{
    public string ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<UserAddress> Addresses { get; set; }
}

public class UserAddress
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
}

AutoMapper Mapping:

CreateMap<UserDetailDto, UserDetail>()
    .ForMember(dest => dest.ID, src => src.MapFrom(_ => _.ID))
    .ForMember(dest => dest.FirstName, src => src.MapFrom(_ => _.FirstName))
    .ForMember(dest => dest.LastName, src => src.MapFrom(_ => _.LastName));

In the above, a user can have multiple addresses. So from database, there will be multiple records for a user with different Address1 and Address2 but same ID, FirstName and LastName.

So, I need to do the mapping in such a way the for a user though there could be multiple records but after mapping it should have a single record with list of its addresses.

I am not sure how this can be achieved or even supported. Any help is really appreciated.

1

There are 1 best solutions below

9
Yong Shun On BEST ANSWER

You can implement a custom type converter to map from List<UserDetailDto> to List<UserDetail>.

public class UserDetailDtoListToUserDetailListConverter : ITypeConverter<List<UserDetailDto>, List<UserDetail>>
{
    public List<UserDetail> Convert(List<UserDetailDto> source, List<UserDetail> destination, ResolutionContext context)
    {
        destination = new List<UserDetail>();

        foreach (var group in source.GroupBy(e => e.ID))
        {
            var firstItem = group.FirstOrDefault();

            var dto = context.Mapper.Map<UserDetail>(firstItem);
            dto.Addresses = context.Mapper.Map<List<UserAddress>>(group);

            destination.Add(dto);
        }

        return destination;
    }
}

Mapping rules:

CreateMap<UserDetailDto, UserDetail>();
            
CreateMap<UserDetailDto, UserAddress>();

CreateMap<List<UserDetailDto>, List<UserDetail>>()
    .ConvertUsing<UserDetailDtoListToUserDetailListConverter>();

Usage:

var userDetailList = _mapper.Map<List<UserDetail>>(userDetailDtoList);

Note that by default AutoMapper will automatically map from the source object to the destination object with the same member name, so you don't need to specify the member mapping with the same name.