question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ArgumentException with Complex Delegation of Compiled Query

See original GitHub issue

File a bug

I am kicking the tires on Compiled Queries, and I appear to have run into a potential bug. Reporting it here for your review.

In essence, I am delegating the resolution of the IQueryable<T> used for the compiled query expression to other components. This works, but there does appear to be a limit to how far this can go currently.

When this condition happens, the wrong type appears to be evaluated, leading to the exception.

I have actually seen this type of exception before in my usage with EfCore, but the scenarios were far too complex to report at the time. Luckily I have been able to capture it here in a much more simpler format to investigate.

Include your code

I’ve created a sample project with a passing test and a failing test here: https://github.com/Mike-E-angelo/Stash/tree/master/EfCore.CompiledQuery.ArgumentException

Include stack traces


System.ArgumentException
Expression of type 'Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor+QueryingEnumerable`1[EfCore.CompiledQuery.ArgumentException.Subject]' cannot be used for parameter of type 'System.Linq.IQueryable`1[EfCore.CompiledQuery.ArgumentException.Subject]' (Parameter 'arg2')
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Invoke(Expression expression, Expression arg0, Expression arg1, Expression arg2)
   at System.Linq.Expressions.InvocationExpression3.Rewrite(Expression lambda, Expression[] arguments)
   at System.Linq.Expressions.ExpressionVisitor.VisitInvocation(InvocationExpression node)
   at System.Linq.Expressions.InvocationExpression.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.CreateCompiledAsyncQuery[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledAsyncEnumerableQuery`2.CreateCompiledQuery(IQueryCompiler queryCompiler, Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryBase`2.<>c.<EnsureExecutor>b__6_0(CompiledQueryBase`2 t, TContext c, LambdaExpression q)
   at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam1,TParam2,TParam3,TValue](TValue& target, TParam1 param1, TParam2 param2, TParam3 param3, Func`4 valueFactory)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryBase`2.EnsureExecutor(TContext context)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryBase`2.ExecuteCore(TContext context, CancellationToken cancellationToken, Object[] parameters)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryBase`2.ExecuteCore(TContext context, Object[] parameters)
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledAsyncEnumerableQuery`2.Execute[TParam1](TContext context, TParam1 param1)
   at EfCore.CompiledQuery.ArgumentException.Form`2.Get(In`1 parameter) in ...\EfCore.CompiledQuery.ArgumentException\EfCore.CompiledQuery.ArgumentException\Class1.cs:line 249
   at EfCore.CompiledQuery.ArgumentException.Invoke`3.Get(TIn parameter) in ...\EfCore.CompiledQuery.ArgumentException\EfCore.CompiledQuery.ArgumentException\Class1.cs:line 231
   at EfCore.CompiledQuery.ArgumentException.Evaluate`3.Get(TIn parameter)
   at EfCore.CompiledQuery.ArgumentException.CompiledQueryTests.DoesNotWork() in ...\EfCore.CompiledQuery.ArgumentException\EfCore.CompiledQuery.ArgumentException\CompiledQueryTests.cs:line 46
   at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_1.<<InvokeTestMethodAsync>b__1>d.MoveNext() in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\Runners\TestInvoker.cs:line 264
--- End of stack trace from previous location ---
   at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\ExecutionTimer.cs:line 48
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in C:\Dev\xunit\xunit\src\xunit.core\Sdk\ExceptionAggregator.cs:line 90

Include verbose output

NA

Include provider and version information

EF Core version: 6.0.0-rc.1.21416.1 Database provider: Microsoft.EntityFrameworkCore.InMemory Target framework: net6.0 Operating system: Windows 10 IDE: Visual Studio 2022 Preview 3.1

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:17 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
smitpatelcommented, Aug 24, 2021

EF Core has certain visitor for certain patterns to remove invocation expression. See https://github.com/dotnet/efcore/blob/release/6.0/src/EFCore/Query/Internal/InvocationExpressionRemovingExpressionVisitor.cs

The invocation pattern is only useful when a custom selector needs to be applied on a reference navigation which is not composable in LINQ any longer. For other patterns when a simpler and better expression tree can be generated using invocation expression is unsupported scenario. The specific reason you are running into type mismatch for parameter “arg2” is that the method is being evaluated on client side. I hope this explains why some of the queries worked for you. The way expression trees are being created above is not same as tree created by compiler from a LINQ query, it is not the way trees are created dynamically (there are many libraries which integrate on top of EF and generate queries dynamically, eg. OData/AutoMapper). We don’t intend to spend time in supporting the pattern represented above since we consider it bad design.

As suggested above, if you really want to construct dynamic trees then more understanding in how to create expression tree will be useful. The current design of passing around func is not supported.

1reaction
smitpatelcommented, Aug 24, 2021

In ideal world, yes it should throw compile exception but in real world things are bit different. When you write a complex expression tree and pass it to EF.CompiledQuery the delegate returned from it would take correct type, so this doesn’t cause compilation error. But in the complex expression tree written if you have a queryable subquery which would terminate (for whatever reason like applying a terminating result operator or ToList or passing it as argument to a function which EF doesn’t understand), EF will convert the queryable to IAsyncEnumerable after query translation. Now the tree you had earlier which was compile fine is incorrect since you don’t have queryable anymore. If you are using such method inside the expression passed to CompiledQuery the method needs to take type which can accommodate this change. Since queryable derives from IEnumerable, you need to make sure that parts of query which will get converted from queryable to EF Core’s enumerable are used as enumerable inside expression.

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - CompiledQuery throws ArgumentException
I'm trying to use a very simple pre-compiled query within an extension method to retrieve data using LINQ to SQL. SytelineRepository is my ......
Read more >
EF.CompileQuery SingleQueryingEnumerable cannot be ...
EF.CompileQuery returns a func which takes parameter and return result. The result type cannot be IQueryable as the compiled query delegate ...
Read more >
How to fix the ArgumentException 'Incompatible Delegate ...
Depending on the type and scope of error you're looking for, the normal way to find it would be one of these: 1....
Read more >
Run EF Core Queries on SQL Server From Blazor WebAssembly
For some reason, comparing a complex expression based on a query was failing. And I realized it's not always practical to compare the...
Read more >
4. Advanced C# - C# 7.0 in a Nutshell [Book]
The ability to compile to an expression tree, by assigning to Expression<T>. To write an anonymous method, you include the delegate keyword followed...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found