Search code examples
c#lambdaautomapperautomapper-8

Automapper Expression Mapping Issue


Expression mapping using AutoMapper.Extensions.Expression is not mapping the expression.

Here are my models:

public class UserDto
{
    public int Id { get; set; }
    public User User { get; set; }
    //other info
}

public class User
{
    public string Email { get; set; }
    //other info
}


public class UserEntity
{
    public int Id { get; set; }
    public string Email { get; set; }
    //other info
}

My mappers:

public static class MapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(cfg =>
        {
            cfg.AddProfile(new UserDtoProfile());
        });
    }
}

internal class UserDtoProfile : Profile
{
    public UserDtoProfile()
    {
        CreateMap<UserDto, UserEntity>()
            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.User.Email));

        CreateMap<UserEntity, UserDto>()
            .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.User, opt => opt.MapFrom(src => Mapper.Map<UserEntity>(src)));

        CreateMap<UserEntity, User>()
           .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)).ReverseMap();
    }
}

Add a snippet to reproduce the issue:

static void Main(string[] args)
{
    MapperConfiguration.Configure();
    var email = "[email protected]";
    Expression<Func<UserDto, bool>> filterExpression = x => x.User.Email == email;
    var expression = Mapper.Map<Expression<Func<UserEntity, bool>>>(filterExpression);
    Console.WriteLine("Old Expression : " + filterExpression.Body);
    Console.WriteLine("New Expression : " + expression.Body);
    Console.Read();
}

The output of this is:

Old Expression : (x.User.Email == "asd")
New Expression : (x.User.Email == "asd")

However, I'm expecting it to output:

Old Expression : (x.User.Email == "asd")
New Expression : (x.Email == "asd")

The particular lines that aren't working as I expect are:

Expression<Func<UserDto, bool>> filterExpression = x => x.User.Email == email;
var expression = Mapper.Map<Expression<Func<UserEntity, bool>>>(filterExpression);

I'm using AutoMapper v8.0.0 and AutoMapper.Extensions.Expression v2.0.0


Solution

  • You forgot to configure the Expression mapping. Your setup should be:

    Mapper.Initialize(cfg =>
    {
        cfg.AddExpressionMapping();
        cfg.AddProfile(new UserDtoProfile());
    });
    

    I haven't really used AutoMapper, and have never used the expression mapping, but as per this github issue, the mapping appears to be backwards for expressions. Your current mapping won't work, and will crash when executing. You'll need to change the mapping to be:

    internal class UserDtoProfile : Profile
    {
        public UserDtoProfile()
        {
            CreateMap<UserDto, UserEntity>()
                .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
                .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.User.Email))
                .ReverseMap();
    
            CreateMap<UserEntity, User>()
               .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)).ReverseMap();
        }
    }
    

    Running this gives the output:

    Old Expression : (x.User.Email == "asd")
    New Expression : (x.Email == "asd")