-
Notifications
You must be signed in to change notification settings - Fork 392
Description
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.