3

How to map objects inherited from one interface to objects inherited from another interface.

I have such code structure

public interface IDataTranslatable
{
    List<DataTranslation> SpanishDataTranslations {get;set;}
}

public interface IDataTranslatableDto
{
    List<DataTranslationDto> DataTranslations { get; set; }
}

objects DataTranslation and DataTranslationDto have the same properties. I have many objects inherited from IDataTranslatable and IDataTranslatableDto interfaces. For example

public class Category : IDataTranslatable
{
    public string Name { get; set; }
    public ICollection<DataTranslation> SpanishDataTranslations { get; set; } = new List<DataTranslation>();
}

public class CategoryDto : IDataTranslatableDto
{
    public string Name { get; set; }
    public List<DataTranslationDto> DataTranslations { get; set; } = new List<DataTranslationDto>();
}

The best implementation for me would be something like that

config.CreateMap<IDataTranslatable, IDataTranslatableDto>()
.ForMember(dest => dest.DataTranslations, opts => opts.MapFrom(src => src.SpanishDataTranslations));

By this I mean that any object inherited from IDataTranslatable has to be mapped to object inherited IDataTranslatableDto to corresponding fields.

But this won't work, So I've tried to map like that

config.CreateMap<IDataTranslatable, CategoryDto>()
.ForMember(dest => dest.DataTranslations, opts => opts.MapFrom(src => src.SpanishDataTranslations));

Current using

public class AutoMapperConfiguration : IAutoMapperConfiguration
{
    public void Configure(IMapperConfigurationExpression config)
    {
        IDataTranslatableMappings(config);
    }

    private void IDataTranslatableMappings(IMapperConfigurationExpression config)
    {
        var mapCategory = config.CreateMap<Category, CategoryDto>().ForMember(dest => dest.DataTranslations, opts => opts.MapFrom(src => src.SpanishDataTranslations));
    }
}

This variant doesn't work as well. I've tried to explain my idea, how would be better to do it?

2
  • Can you please also show the usage of the mapper? (Are you mapping to the interface or the concrete class?) Commented Jun 26, 2019 at 9:10
  • @Dominik In case if it is not possible to map by interfaces, I've just map it direct. Thank you for the help! Commented Jun 26, 2019 at 13:09

1 Answer 1

6

You can configure it the following way:

Mapper.Initialize(config =>
{
    config.CreateMap<IDataTranslatable, IDataTranslatableDto>()
                .ForMember(x => x.DataTranslations, y => y.MapFrom(src => src.SpanishDataTranslations));
                
    config.CreateMap<Category, CategoryDto>()
                .IncludeBase<IDataTranslatable, IDataTranslatableDto>();                    

    config.CreateMap<DataTranslation, DataTranslationDto>();
});

And the usage of it:

var translation = new DataTranslation()
{
    Test = "Foo"
};

IDataTranslatable category = new Category()
{
     SpanishDataTranslations = new List<DataTranslation> { translation }
};

var result = Mapper.Map<IDataTranslatableDto>(category);

You will be forced to add every implementation of IDataTranslatable and IDataTranslatableDto to the mapping configuration.


Update

From version 8.0 and above, you can use IncludeDerived on your base type and therefore no longer need to explicitly declare all implementations of your interface.

Sign up to request clarification or add additional context in comments.

2 Comments

Should IncludeDerived not work for this or am imisunderstanding??
@sommmen True, it's only included from Version 8.0 and higher. I believe most ppl. still use <8.0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.