Search code examples
c#automapper.net-6.0

AutoMapper: When mapping to the same destination member from 2 different source members, the second source member is not mapping


I am trying to map a SourceCar model containing multiple types, to a DestinationCar but I am struggling when trying to map to the same object from 2 different sources. The Model DestinationDriverInfo should hold the value for both of its properties in the mapping result, but it only holds a value for NumberOfYearsDriving not for NumberOfClaims.

Models and Mapping Configuration below:

image

Execution:

enter image description here

Expected Result:

Properties belonging to DestinationDriverInfo should both be populated. (NumberOfYearsDriving & NumberOfClaims)

Actual Result:

Only NumberOfYearsDriving property inside DestinationDriverInfo is mapped from source.

PS: The source models cannot be changed.

Here is an executable example: https://gist.github.com/ReeceDigital/1944cfea50900de9feb83df8112e1266

Thanks!


Solution

  • Here is your config:

    var config = new MapperConfiguration(c =>
    {
        c.CreateMap<SourceCar, DestinationCar>()
            .ForMember(dest => dest.Driver, opt => opt.MapFrom(src => src.Info));
                    
        c.CreateMap<SourceInfo, DestinationDriver>()
            .ForMember(dest => dest.DriverInfo, opt => opt.MapFrom(src => src.GeneralInfo));
                    
        c.CreateMap<SourceGeneralInfo, DestinationDriverInfo>()
            .ForMember(dest => dest.NumberOfClaims, opt => opt.MapFrom(src => src.Claim.NumClaims))
            .ForMember(dest => dest.NumberOfYearsDriving, opt => opt.MapFrom(src => src.Driver.NumDriving));
    });
    

    So you can map SourceInfo with nested objects and its properties directly to the DestinationDriver properties and it will work with current structure.

    If you do not need to be able to convert objects from SourceClaim to DestinationDriverInfo or from SourceDriver to DestinationDriverInfo additionally directly without parent objects, this will enough. Otherwise you can also add these mappings to the configuration:

    var config = new MapperConfiguration(c =>
    {
        c.CreateMap<SourceCar, DestinationCar>()
            .ForMember(dest => dest.Driver, opt => opt.MapFrom(src => src.Info));
                    
        c.CreateMap<SourceInfo, DestinationDriver>()
            .ForMember(dest => dest.DriverInfo, opt => opt.MapFrom(src => src.GeneralInfo));
                    
        c.CreateMap<SourceGeneralInfo, DestinationDriverInfo>()
            .ForMember(dest => dest.NumberOfClaims, opt => opt.MapFrom(src => src.Claim.NumClaims))
            .ForMember(dest => dest.NumberOfYearsDriving, opt => opt.MapFrom(src => src.Driver.NumDriving));
    
        c.CreateMap<SourceDriver, DestinationDriverInfo>()
            .ForMember(dest => dest.NumberOfYearsDriving, opt => opt.MapFrom(src => src.NumDriving))
            .ForMember(dest => dest.NumberOfClaims, opt => opt.Ignore());
    
        c.CreateMap<SourceClaim, DestinationDriverInfo>()
            .ForMember(dest => dest.NumberOfClaims, opt => opt.MapFrom(src => src.NumClaims))
            .ForMember(dest => dest.NumberOfYearsDriving, opt => opt.Ignore());
    });