Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automapper nested mapping

Tags:

c#

automapper

I've read the nested mapping wiki page but it appears to not like multiple levels of nesting. I've got the following maps created and classes defined.

AutoMapper.Mapper.CreateMap<Address, AddressDTO>();
AutoMapper.Mapper.CreateMap<MatchCompanyRequest, MatchCompanyRequestDTO>();

public class MatchCompanyRequest
{
    Address Address {get;set;}
}

public class MatchCompanyRequestDTO
{
    public CompanyInformationDTO {get;set;}
}

public class CompanyInformationDTO {get;set;}
{
    public string CompanyName {get;set;}
    public AddressDTO Address {get;set;}
}

But the following code...

// works
matchCompanyRequestDTO.companyInformationDTO.Address =
    AutoMapper.Mapper.Map<Address, AddressDTO>(matchCompanyRequest.Address);

// fails
matchCompanyRequestDTO =
    AutoMapper.Mapper
        .Map<MatchCompanyRequest, MatchCompanyRequestDTO>(matchCompanyRequest);

Does this deep nesting work and I have it configured improperly? Or is this kind of nesting not yet supported?

-- Edit

For anyone interested, I am not in control of the DTOs.

like image 734
ryan Avatar asked Oct 24 '11 14:10

ryan


People also ask

How does AutoMapper work in C#?

AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.

What is AutoMapper profile?

automapper Profiles Basic Profile Profiles permit the programmer to organize maps into classes, enhancing code readability and maintainability. Any number of profiles can be created, and added to one or more configurations as needed. Profiles can be used with both the static and instance-based APIs.

What is reverse map in AutoMapper?

The Automapper Reverse Mapping is nothing but the two-way mapping which is also called as bidirectional mapping. As of now, the mapping we discussed are one directional means if we have two types let's say Type A and Type B, then we Map Type A with Type B.


2 Answers

It lacks the mapping from Address to CompanyInformationDTO, as those objects are on the same nest-level.

The map is created for MatchCompanyRequest -> MatchCompanyRequestDTO, but it is unable to figure out whether it can map Address to CompanyInformationDTO.

So your MatchCompanyRequestDTO could in fact have same declaration as your CompanyInformationDTO:

public class MatchCompanyRequestDTO
{
    public string CompanyName {get;set;}
    public AddressDTO Address {get;set;}
}

This of course only affects you if you want to use automatic mapping. You still can configure your maps manually, but it seems like the DTOs should be fixed instead, let's try anyway:

public class CustomResolver : ValueResolver<Address, CompanyInformationDTO>
{
    protected override CompanyInformationDTO ResolveCore(Address source)
    {
        return new CompanyInformationDTO() { Address = Mapper.Map<Address, AddressDTO>(source) };
    }
}
// ...

AutoMapper.Mapper.CreateMap<MatchCompanyRequest, MatchCompanyRequestDTO>()
    .ForMember(dest => dest.companyInformationDTO, opt => opt.ResolveUsing<CustomResolver>().FromMember(src => src.Address)); // here we are telling to use our custom resolver that converts Address into CompanyInformationDTO
like image 109
Bartosz Avatar answered Oct 13 '22 08:10

Bartosz


The important thing is you define how deeper is your navigation, to previne the stackoverflow problems. Imagine this possibility:

You have 2 entities Users and Notifications in NxN model (And you have DTOs object to represent that), when you user auto mapper without set MaxDepth in you mapper expression, "Houston we have a problem" :).

The code below show a workaround to resolve this for all Mappers. If you want can be defined to each mapper. Like this Question

Solution 1 (Global Definition)

public class AutoMapperConfig
{
    public static void RegisterMappings()
    {
        Mapper.Initialize(mapperConfiguration =>
        {
            mapperConfiguration.AddProfile<DomainModelToYourDTOsMappingProfile>();
            mapperConfiguration.AddProfile<YourDTOsToDomainModelMappingProfile>();
            mapperConfiguration.AllowNullCollections = true;
            mapperConfiguration.ForAllMaps(
                (mapType, mapperExpression) => {
                    mapperExpression.MaxDepth(1);
                });
        }
    }

Solution 2 (For each Mapper)

 public class AutoMapperConfig
 {
     public static void RegisterMappings()
     {
         Mapper.CreateMap<User, DTOsModel>()
               .MaxDepth(1);
     }
 }
like image 38
Rodrigo Couto Avatar answered Oct 13 '22 08:10

Rodrigo Couto