4
votes

I am trying to use AutoMapper to map between two models in an expression, but receiving an error from AutoMapper: "Error Mapping Types" with an Inner Exception Message of "Object reference not set to an instance of an object."

I set up my configuration and defined the mapping by following the wiki on Github:

Configuration

Expression Translation

Below is a very simplified example that produces the error using version AutoMapper 5.1.1.

Models to Map

Note: I only need to map from Model1 to Model2.

public class Model1
{
    public int Id { get; set; }
}

public class Model2
{
    public int Id { get; set; }
} 

Configuration:

public static class AutoMapperConfig
{
    public static IMapper Mapper;

    static AutoMapperConfig()
    {
        var config = new MapperConfiguration(c => {
          // Produces error
          CreateMap<Model1, Model2>();

          //The below definitions do NOT produce error
          CreateMap<Model1, Model2>().ReverseMap();
          //OR
          CreateMap<Model1, Model2>();
          CreateMap<Model2, Model1>();
          //OR
          CreateMap<Expression<Func<Model1,bool>>, Expression<Func<Model2,bool>>>();

        });

        Mapper = config.CreateMapper();
    }
}

Usage:

Expression<Func<Model1, bool>> model1Expr = x => x.Id == 2;
var model2Expr =  AutoMapperConfig.Mapper.Map<Expression<Func<Model2,bool>>>(model1Expr);

I receive the error at the line that declares the model2Expr variable above.

Error From Elmah :(

[NullReferenceException: Object reference not set to an instance of an object.]
AutoMapper.Mappers.MappingVisitor.PropertyMap(MemberExpression node) +109
AutoMapper.Mappers.MappingVisitor.VisitMember(MemberExpression node) +95
System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor) +14
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) +22
AutoMapper.Mappers.MappingVisitor.VisitBinary(BinaryExpression node) +73
System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor) +14
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) +22
AutoMapper.Mappers.ExpressionMapper.Map(TSource expression, ResolutionContext context) +1534
lambda_method(Closure , Object , Object , ResolutionContext ) +183

[AutoMapperMappingException: Error mapping types.

IMPORTANT: A coworker noted that the error is not encountered when two way mapping is defined (with either ReverseMap or two separate CreateMap statements), or when the mapping is defined explicitly as being between to Expression types. The Expression Translation link above does define two way mapping between the models, but does not explicitly mention requiring it.

Question:

Am I somehow messing up the configuration and/or map definition, or are two way mapping definitions required when mapping between objects in expressions and the wiki is just not explicitly stating it?


UPDATE: I opened an issue on AutoMapper GitHub. As of right now it seems that

Yes the order is backwards when doing expression translation.

Basically this means that if you want to map between expressions, create a mapping definition in the opposite direction of your desired mapping:

CreateMap<Model2, Model1>();
//....
Expression<Func<Model1, bool>> model1Expr = x => x.Id == 2;
var model2Expr =  AutoMapperConfig.Mapper.Map<Expression<Func<Model2,bool>>>(model1Expr);
1
The usage is different from the map which is configured to map from Model1 object to Model2 object.Win
@Win I just tried defining a one way map between the Expressions themselves, and I did not receive the error. I did not try it before because from what I understand in the Expression Translation wiki, the map definition between the objects would suffice. Is it possible that this is just a case of incomplete documentation?karol
Automapper is designed to map from properties of an object to another object. Why would like to map from an expression tree to another? It should not be the job of Automapper.Win
Here's a highly-related question that might give a little insight.Will Ray
@Win In my particular case, I have a DTO that is a representation of an Entity model. I create a lambda expression with the DTO in a presentation layer controller(ASP.NET MVC). That lambda expression is then passed as a parameter to a business layer method. The business layer method then needs to convert/map from the DTO expression to an Entity model expression so that I can use it with Entity Framework.karol

1 Answers

1
votes

You need to call the ReverseMap as below:

static AutoMapperConfig()
{
    var config = new MapperConfiguration(c => {
      CreateMap<Model1, Model2>().ReverseMap(); // <======
    });

    Mapper = config.CreateMapper();
}