DrSheikh
DrSheikh

Reputation: 9

AutoMapper different level

Trying to map from Customer to CustomerDto but having issues with that extra layer in the source (I have no control over the source so I cannot align the two unfortunately).

public class Customer
{
    public string Name { get; set; }
    public AddressSet AddressSet { get; set; }
}

public class AddressSet
{
    public AddressSetResults[] AddressSetResults { get; set; }    
}

public class AddressSetResults
{
    public string Street { get; set; }
    public string HouseNumber { get; set; }
}

public class CustomerDto
{
    public string Name { get; set; }
    public AddressDto AddressDto { get; set; }
}

public class AddressDto
{
    public string Street { get; set; }
    public string HouseNumber { get; set; }
}

The following does not work for the AddressDto, any idea what I'm missing?

CreateMap<Customer, CustomerDto>()
 .ForMember(dest => dest.AddressDto , opt => opt.MapFrom(src => src.AddressSet.AddressSetResults))

Upvotes: 0

Views: 31

Answers (1)

Prolog
Prolog

Reputation: 3364

Two things:

1) Missing map from AddressSetResults to AddressDto

In order to map inner address you need to create map for these inner types as well:

CreateMap<AddressSetResults, AddressDto>();

2) Map from an element of AddressSetResults array, not from the array itself

This method:

.ForMember(
    dest => dest.AddressDto, 
    opt => opt.MapFrom(src => src.AddressSet.AddressSetResults))

tells AutoMapper to map to AddressDto from AddressSetResults which is an array of AddressSetResults. This is incorrect, as AutoMapper will not know how to map from array of elements to just one element. Unless you create a map for that too, which would not be a good solution.

Assuming that AddressSetResults will contain up to one address you can fix that adding just one more call FirstOrDefault() to the end of mapping expression:

.ForMember(
    dest => dest.AddressDto, 
    opt => opt.MapFrom(src => src.AddressSet.AddressSetResults.FirstOrDefault()))

FirstOrDefault() needs System.Linq namespace.

Why not just First()? If source AddressSetResults array would contain no elements, then mapping would fail resulting in exception as no elements would be found to satisfy the First() method call. Making it resistant to no elements scenario with FirstOrDefault() is more secure solution.


Final, working configuration:

CreateMap<Customer, CustomerDto>()
    .ForMember(
        dest => dest.AddressDto,
        opt => opt.MapFrom(src => src.AddressSet.AddressSetResults.FirstOrDefault()));
CreateMap<AddressSetResults, AddressDto>();

Upvotes: 1

Related Questions