I have a model which I'm trying to map using Automapper's Queryable Extensions. For one of the properties we need to do a firstordefault, however this is failing with a NullReferenceException. This works fine with EF6 however is failing here. However, if I map this to a collection instead of an object it works fine.
Exception message:
Stack trace:
NullReferenceException: Object reference not set to an instance of an object.
Microsoft.EntityFrameworkCore.Extensions.Internal.EFPropertyExtensions.CreateEFPropertyExpression(Expression target, Type propertyDeclaringType, Type propertyType, string propertyName, bool makeNullable)
Microsoft.EntityFrameworkCore.Extensions.Internal.EFPropertyExtensions.CreateEFPropertyExpression(Expression target, IPropertyBase property, bool makeNullable)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.EntityEqualityRewritingExpressionVisitor.RewriteNullEquality(ExpressionType nodeType, Expression nonNullExpression)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.EntityEqualityRewritingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
System.Linq.Expressions.ExpressionVisitor.Visit<T>(ReadOnlyCollection<T> nodes, Func<T, T> elementVisitor)
System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
Remotion.Linq.Clauses.SelectClause.TransformExpressions(Func<Expression, Expression> transformation)
Remotion.Linq.QueryModel.TransformExpressions(Func<Expression, Expression> transformation)
Microsoft.EntityFrameworkCore.Query.Internal.QueryOptimizer.Optimize(QueryCompilationContext queryCompilationContext, QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.OptimizeQueryModel(QueryModel queryModel, bool asyncQuery)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.OptimizeQueryModel(QueryModel queryModel, bool asyncQuery)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor<TResult>(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Storage.Database.CompileAsyncQuery<TResult>(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQueryCore<TResult>(Expression query, IQueryModelGenerator queryModelGenerator, IDatabase database)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+<>c__DisplayClass22_0<TResult>.<CompileAsyncQuery>b__0()
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore<TFunc>(object cacheKey, Func<Func<QueryContext, TFunc>> compiler)
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddAsyncQuery<TResult>(object cacheKey, Func<Func<QueryContext, IAsyncEnumerable<TResult>>> compiler)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQuery<TResult>(Expression query)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync<TResult>(Expression query)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync<TResult>(Expression expression)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<TResult>.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
System.Linq.AsyncEnumerable.Aggregate_<TSource, TAccumulate, TResult>(IAsyncEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> accumulator, Func<TAccumulate, TResult> resultSelector, CancellationToken cancellationToken)
FinBrook.Application.Helpers.QueryProjectAsync<TEntity, classType>(DbSet<TEntity> context, NameValueCollection query, Expression<Func<TEntity, bool>> match) in Helpers.cs
+
result.Result = await context.Where(match).ProjectTo<classType>().AsNoTracking().ToListAsync<classType>();
FinBrook.Application.GetAllDealsQueryHandler.Handle(GetAllDealsQuery request, CancellationToken cancellationToken) in GetAllDealsQueryHandler.cs
+
return await Helpers.QueryProjectAsync<Deal, DealDTO>(_context.Deals, request.Query);
FinBrook.Application.RequestPerformanceBehaviour<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) in RequestPerformanceBehaviour.cs
+
var response = await next();
MediatR.Pipeline.RequestPreProcessorBehavior<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
FinBrook.API.DealsController.GetAllDealsAsync() in DealsController.cs
+
var result = await Mediator.Send(new GetAllDealsQuery()
lambda_method(Closure , object )
Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable+Awaiter.GetResult()
Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor+AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ExceptionContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
```c#
class Program
{
static void Main(string[] args)
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap
.ForMember(d => d.Target, opt => opt.MapFrom(c => c.CarCollections.Where(x => x.CarType == CarType.VAN).FirstOrDefault()));
cfg.CreateMap
cfg.CreateMap
cfg.CreateMissingTypeMaps = false;
});
Mapper.AssertConfigurationIsValid();
Mapper.Configuration.CompileMappings();
var optionsBuilder = new DbContextOptionsBuilder
optionsBuilder.UseSqlServer("Server=(LocalDb)\MSSQLLocalDB;Database=TestingCore;Trusted_Connection=true;MultipleActiveResultSets=true");
var dbContext = new TestContext(optionsBuilder.Options);
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
dbContext.Vehicles.Add(new Vehicle { CarCollections = new List
dbContext.SaveChanges();
var result = dbContext.Vehicles.Where(x => x.ID == 1).ProjectTo
}
}
public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> options) : base(options)
{
}
public DbSet<Vehicle> Vehicles { get; set; }
}
public enum CarType
{
VAN
}
public class Car
{
public int ID { get; set; }
public string Title { get; set; }
}
public class CarCollection
{
public int ID { get; set; }
public Car Car { get; set; }
public CarType CarType { get; set; }
}
public class Vehicle
{
public int ID { get; set; }
public virtual ICollection<CarCollection> CarCollections { get; set; }
}
public class VehicleDTO
{
public int ID { get; set; }
public CarCollectionDTO Target { get; set; }
}
public class CarDTO
{
public string Title { get; set; }
}
public class CarCollectionDTO
{
public CarDTO Car { get; set; }
}
```
EF Core version: 2.1.1
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: Visual Studio 2017 15.7.5
I modified the repo to exclude automapper.
@maganuk If you need to do this in the future, check out https://stackoverflow.com/questions/50682568/automapper-select-expression-translation/50784072#50784072
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace EFCoreBugs
{
class Program
{
static void Main(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<TestContext>();
optionsBuilder.UseSqlServer("Server=(LocalDb)\\MSSQLLocalDB;Database=TestingCore;Trusted_Connection=true;MultipleActiveResultSets=true");
var dbContext = new TestContext(optionsBuilder.Options);
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
dbContext.Vehicles.Add(new Vehicle { CarCollections = new List<CarCollection> { new CarCollection { Car = new Car() { Title = "test" }, CarType = CarType.VAN } } });
dbContext.SaveChanges();
var result = dbContext.Vehicles
.Where(x => x.ID == 1)
.Select(dtoVehicle =>
new
{
__Target = dtoVehicle.CarCollections
.Where(x => ((int)(x.CarType)) == 0)
.FirstOrDefault(),
ID = dtoVehicle.ID
})
.Select(dtoLet =>
new VehicleDTO()
{
ID = dtoLet.ID,
Target = dtoLet.__Target == null ? null : new CarCollectionDTO()
{
Car = dtoLet.__Target.Car == null ? null : new CarDTO()
{
Title = dtoLet.__Target.Car.Title
}
}
})
.ToList();
}
}
public class TestContext : DbContext
{
public TestContext(DbContextOptions<TestContext> options) : base(options)
{
}
public DbSet<Vehicle> Vehicles { get; set; }
}
public enum CarType
{
VAN
}
public class Car
{
public int ID { get; set; }
public string Title { get; set; }
}
public class CarCollection
{
public int ID { get; set; }
public Car Car { get; set; }
public CarType CarType { get; set; }
}
public class Vehicle
{
public int ID { get; set; }
public virtual ICollection<CarCollection> CarCollections { get; set; }
}
public class VehicleDTO
{
public int ID { get; set; }
public CarCollectionDTO Target { get; set; }
}
public class CarDTO
{
public string Title { get; set; }
}
public class CarCollectionDTO
{
public CarDTO Car { get; set; }
}
}
@smitpatel is there any workaround this issue for now?
@ajcvickers will the regression not be fixed for 2.2? Any workarounds till then?
Surely this needs to be fixed by 2.2 at the latest?
Investigate for 2.2.
Submitted a fix for 2.2
We should consider this for servicing.
@smitpatel The branch is now ready for this to be merged.
@smitpatel just upgraded to 2.1.4 and tried running the query in the first post, throwing a different error now:
System.InvalidCastException
HResult=0x80004002
Message=Unable to cast object of type 'System.Int32' to type 'EFCoreBugs.CarCollection'.
Source=Microsoft.EntityFrameworkCore.Relational
StackTrace:
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at EFCoreBugs.Program.Main(String[] args)
The same is happening with 2.2-preview-2.
Marking for re-triage. Confirmed both the repros above are not fixed in 2.1.5.
Re-opening to look at again in 2.2.
related to https://github.com/aspnet/EntityFrameworkCore/issues/6478 - we fixed it for MemberExpression but not for EF.Property expressions
fixed in 7e28f43dc79205aae8a74e3e53adf628aa25174f
Most helpful comment
Submitted a fix for 2.2
We should consider this for servicing.