Automapper: Exception when using ProjectTo on entity with an inner entity with a list of entites

Created on 27 Jan 2020  路  4Comments  路  Source: AutoMapper/AutoMapper

Source/destination types

#region Entities
public abstract class BaseEntity {
    [Key]
    public int Id { get; set; }
}

public class Alpha : BaseEntity {
    public Bravo Bravo { get; set; }
    public int BravoId { get; set; }
}

public class Bravo : BaseEntity {
    public List<Charlie> Charlies { get; set; }
}

public class Charlie : BaseEntity { }
#endregion

#region DTOs
public abstract class BaseDto {
    public int Id { get; set; }
}

public class AlphaDto : BaseDto {
    public BravoDto Bravo { get; set; }
}

public class BravoDto : BaseDto {
    public List<CharlieDto> Charlies { get; set; }
}

public class CharlieDto : BaseDto { }
#endregion

Mapping configuration

CreateMap<Alpha, AlphaDto>().ReverseMap();
CreateMap<Bravo, BravoDto>().ReverseMap();
CreateMap<Charlie, CharlieDto>().ReverseMap();

Versions: AutoMapper 9.0.0 and 9.1.0-ci-01617 and EF Core (with InMemory DB) 3.0.0

Expected behavior

No exceptions.

Actual behavior

The following exception is thrown (click to open):

System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=Microsoft.EntityFrameworkCore.InMemory
  StackTrace:
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryExpressionTranslatingExpressionVisitor.IsConvertedToNullable(Expression result, Expression original)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryExpressionTranslatingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
   at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
   at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryExpressionTranslatingExpressionVisitor.VisitConditional(ConditionalExpression conditionalExpression)
   at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryExpressionTranslatingExpressionVisitor.Translate(Expression expression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)
   at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.Translate(InMemoryQueryExpression queryExpression, Expression expression)
   at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
   at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ProjectToTest.MinimalTest.Test() in D:\Some\File\Path\ProjectTo\MinimalTest.cs:line 134

Steps to reproduce

var alphas = dbContext.Alphas
    .ProjectTo<AlphaDto>(Mapper.ConfigurationProvider)
    .ToList();

Full source code for a standalone repro here:
https://gist.github.com/BaerMitUmlaut/f64838d9d79881ee98dbb23c3a5a1840

Additional information

  • The error does not happen if Bravo only contains a single Charlie instead of a list of Charlies
  • The error does not happen if Alpha contains a list of Bravos instead of just a single Bravo
  • The error does not happen with a SqlServer based database

The latter might mean that it's actually a bug in the InMemory DB, however manually mapping like the following works just fine:

var alphas = dbContext.Alphas
    .Include(alpha => alpha.Bravo)
    .ThenInclude(bravo => bravo.Charlies)
    .Select(alpha => Mapper.Map<AlphaDto>(alpha))
    .ToList();
Assert.NotEmpty(alphas);
Question

All 4 comments

That looks like an EF Core issue. Check the execution plan. Run that as a LINQ statement, without AM. You should get the same result.

Workaround:

 CreateMap<Alpha, AlphaDto>().ForMember(d=>d.Bravo, o=>o.AllowNull()).ReverseMap();

Thank you for the quick response!

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings