Skip to content

InvalidOperationException when trying to use ProjectToType on EF Core query using AddParameters #309

@CyberBotX

Description

@CyberBotX

I am coming to use Mapster from AutoMapper after finding out about Mapster in a recent search. While it seems to work well for some of my cases, I am having trouble with this case. I was using AutoMapper's parameterization with its Queryable extensions for ProjectTo. While I did find the documentation on Mapster's form of parameterization, I get an exception when doing so. I am using EF Core 5.0.3 with Mapster 7.1.3 and Mapster.EFCore 5.0.0.

My code is roughly as follows:

var config = new TypeAdapterConfig
{
	Compiler = exp => exp.CompileFast()	
};
config.Default.MapToConstructor(true);
config.Default.PreserveReference(true);
config.ForType<ModelItem, ModelItemSearchViewModel>().Map(dest => dest.Retail, src => Math.Ceiling(src.Item.Retail * (decimal)MapContext.Current!.Parameters["retailAdjustment"]));
var nonEntityList = await new Mapper(config).From(context.Entity.Where(e => true)).AddParameters("retailAdjustment", 0.95m).ProjectToType<NonEntity>().ToListAsync();

(Stripped down to the relevant code, assume there was actually a condition in the Where method.)

When I try this in LINQPad, I get the following InvalidOperationException message:

An exception was thrown while attempting to evaluate the LINQ query parameter expression 'Convert(MapContext.Current.Parameters.get_Item("retailAdjustment"), Decimal)'. See the inner exception for more information.

With a stack trace of:

   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.GetValue(Expression expression, String& parameterName)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Evaluate(Expression expression, Boolean generateParameter)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
   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 Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.ExtractParameters(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Mapster.EFCore.MapsterQueryableProvider.ExecuteEnumerableAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Mapster.EFCore.MapsterQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at UserQuery.Main(), line 69

The inner exception is a NullReferenceException with the message:

Object reference not set to an instance of an object.

With a stack trace of:

   at lambda_method2573(Closure )
   at Microsoft.EntityFrameworkCore.Query.Internal.ParameterExtractingExpressionVisitor.GetValue(Expression expression, String& parameterName)

I am unsure if I am actually using this correctly or not. With AutoMapper I could just pass in the parameter as a new anonymous object to its ProjectTo method while having a dummy variable inside of my MapperConfiguration's action. I had assumed what I did above would allow me to do the same with Mapster.

I've also tried the following with the same exceptions as above (using the same config as above):

var nonEntityList = await context.Entity.Where(e => true).BuildAdapter(config).AddParameters("retailAdjustment", 0.95m).ProjectToType<NonEntity>().ToListAsync();

I'd definitely like to switch over to Mapster from AutoMapper, but this problem is preventing me from fully switching. If I am doing this incorrectly, please let me know what the proper way of doing this is. I don't seem to have any trouble with doing this if I exclude out the Map that uses the parameter and don't use BuildAdapter (just going to ProjectToType directly).

I should also note that I did notice issue #131 but it does not seem to solve my issue. In fact, doing so allowed me to set a breakpoint in LINQPad and it shows that MapContext.Current is null, which may explain the NullReferenceException above but I am unsure why, as I am following what was described in the Wiki on using AddParameters. I only seem to get this problem while using EF Core and ProjectToType, though, doing a normal AdaptToType on a normal class (not an EF Core entity), I have no issues using MapContext.Current.Parameters.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions