AutoMapper/AutoMapper.Extensions.ExpressionMapping

Incorrect mapping with ConvertUsing

leowns opened this issue · 3 comments

The mapping for ConvertUsing statements seems not to work correctly for my case. Steps to reproduce:

class Program
{
     static void Main(string[] args)
     {
          var config = new MapperConfiguration
         (
             cfg =>
             {
                 cfg.AddExpressionMapping();

                 cfg.CreateMap<EmployeeDTO, Employee>()
                     .ForMember(d => d.Departments, opt => opt.MapFrom(s => s.DepartmentNumbers))
                     .ReverseMap();

                 cfg.CreateMap<int, Department>()
                     .ForMember(d => d.Number, opt => opt.MapFrom(s => s));

                 cfg.CreateMap<Department, int>()
                     .ConvertUsing(x => x.Number);
             }
         );
         var mapper = new Mapper(config);

         Expression<Func<EmployeeDTO, bool>> exp = x => x.DepartmentNumbers.Any(y => y == 2 || y == 4);
         var expMapped = mapper.Map<Expression<Func<Employee, bool>>>(exp);
     }
}

public class Employee
{
   public List<Department> Departments { get; set; }
}

public class Department
{
   public int Number { get; set; }
}

public class EmployeeDTO
{
   public List<int> DepartmentNumbers { get; set; }
}

The resulting expression expMapped is the following:

{x => x.Departments.Any(y => ((y == value(Department)) OrElse (y == value(Department))))}

But this seems to be wrong because when I apply this expression for example on the SQL database it results in this SQL query:

("t2"."id" = 0) OR ("t2"."id" = 0)

That's not supported. Maybe do this instead:

            var config = new MapperConfiguration
            (
                cfg =>
                {
                    cfg.AddExpressionMapping();

                    cfg.CreateMap<EmployeeDTO, Employee>()
                        .ForMember(d => d.Departments, opt => opt.MapFrom(s => s.DepartmentNumbers))
                        .ReverseMap()
                        .ForMember(d => d.DepartmentNumbers, opt => opt.MapFrom(s => s.Departments.Select(d => d.Number)));
                }
            );

@BlaiseD I thought ConvertUsing is also supported but your code works as well thank you. Is there any documentation where I can find supported mappings?

The sources for mapping expressions are MapFrom, ForPath and the property maps. ConvertUsing does have an expression argument so it may be a candidate for expression mapping - PRs are welcome.

I don't believe this is documented. You may contribute to the documentation here.