0

We have static classes to centralize our expressions

public static Expression<Func<PersonEntity, bool>> IsActivated()
    => pe => pe.ActivatedOn != null;

So we can just write e.g.

  DbContext.Persons
  .AsQueryable()
  .Where(PersonsQuery.IsActivated())
  .SingleOrDefault();

instead of

  .Where(pe => pe.ActivatedOn != null)

Which works in all kind of providers we use (e.g. Entity Framework).

But in Automapper this does not work in a Profile.

.ForMember(p => p.ActivatedPersons,
    opt => opt.MapFrom(e => e.Persons
            .AsQueryable()
            .Where(PersonsQuery.IsActivated())
            .SingleOrDefault()))

This results in

InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.MethodCallExpression1' to type 'System.Linq.Expressions.LambdaExpression'.

If we use

.ForMember(p => p.ActivatedPersons,
    opt => opt.MapFrom(e => e.Persons
            .AsQueryable()
            .Where(pe => pe.ActivatedOn != null)
            .SingleOrDefault()))

it works.

Is there a way we can use our static expressions?

Exception Stack Details:

System.Linq.Expressions.ExpressionExtensions.UnwrapLambdaFromQuote(Expression expression) Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)F 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(ReadOnlyCollection 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) Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor+PendingSelectorExpandingExpressionVisitor.Visit(Expression expression) Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(Expression query) Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query) Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.Process(Expression query) Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor(Expression query) Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery(Expression query, bool async) Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore(IDatabase database, Expression query, IModel model, bool async) Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+<>c__DisplayClass12_0.b__0() Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery(object cacheKey, Func<Func<QueryContext, TResult>> compiler) Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync(Expression query, CancellationToken cancellationToken) Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync(Expression expression, CancellationToken cancellationToken) Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable.GetAsyncEnumerator(CancellationToken cancellationToken) System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable.GetAsyncEnumerator() Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(IQueryable source, CancellationToken cancellationToken)

2
  • Can you show call stack? Commented Feb 20, 2021 at 19:37
  • @SvyatoslavDanyliv sorry, added. Commented Feb 20, 2021 at 19:44

1 Answer 1

2

Looks like it is known EF limitation. You can solve that only by third party extensions.

https://github.com/hazzik/DelegateDecompiler

https://github.com/axelheer/nein-linq

Simple sample using DelegateDecompiler

[Computed]
public static bool IsActivated(PersonEntity pe)
    => pe.ActivatedOn != null;

Automapper

.ForMember(p => p.ActivatedPersons,
    opt => opt.MapFrom(e => e.Persons
            .AsQueryable()
            .Where(pe => PersonsQuery.IsActivated(pe))
            .SingleOrDefault()))

Final query

DbContext.Persons
   .AsQueryable()
   .Where(pe => PersonsQuery.IsActivated(pe))
   .Decompile()
   .SingleOrDefault();

It is important to call Decompile or DecompileAsync

P.S.

I like how it was done by DelegateDecompiler, but nein-linq also usable. Also LINQKit can help here with its Invoke. But everything needs additional call Decompile() or ToInjectable() or AsExpandable() according to library.

Sign up to request clarification or add additional context in comments.

5 Comments

Mh... its weird because it works in EF but not if I use this in the AutoMapper Profile. LINQKit has too much side-effects. So thanks for all your hints I'll check what we do..
@BenjaminAbt, in Automapper variant you defines Expression. So PersonsQuery.IsActivated() is become MethodCallExpression but for parsing that EF expects LambdaExpression. For getting Lambda from MethodCall it should Invoke method - but it doesn't.
Libraries that I have mentioned preprocess ExpressionTree and make EF happy.
We had so many troubles with the generated code with LINQKit.. :-/
LINQKit, is simple library for correcting Expression Tree. Problems in usage is leak of knowledge how LINQ works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.