You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The former works fine in regular EFCore usage, and the latter also works for their intended use case, EF Compiled Queries, in normal use cases where truePredicate does not reference outside values, for example:
Expression<Func<DbContext, bool, User>> buildQueryExpression =
(DbContext dbContext, bool flag) =>
dbContext.Set<User>()
.ConditionalWhere(flag, u => u.Id <= 10)
.FirstOrDefault();
var queryAsync = EF.CompileAsyncQuery(buildQueryExpression.Expand());
var result = await queryAsync(_dbContext, true); // Success
Problem
However, if the truePredicate does reference outside values then it fails, not just for EF Compiled Queries, but also just when Compile()ing the Expand()ed lambda:
Expression<Func<DbContext, bool, int, User>> buildQueryExpression =
(DbContext dbContext, bool flag, int maxId) =>
dbContext.Set<User>()
.ConditionalWhere(flag, u => u.Id <= maxId)
.FirstOrDefault();
var result1 = buildQueryExpression.Compile()(_dbContext, true, 10); // Success
var result2 = buildQueryExpression.Expand().Compile()(_dbContext, true, 10); // Failure
var queryAsync = EF.CompileAsyncQuery(buildQueryExpression.Expand());
var result = await queryAsync(_dbContext, true, 10); // Also failure, same error
We get this error:
System.InvalidOperationException: variable 'maxId' of type 'System.Int32' referenced from scope '', but it is not defined
Note that Expand() is required so EF.CompileAsyncQuery() can translate the query logic, since it doesn't understand ConditionalWhere. Also if I alter ConditionalWhereExpression to just return query.Where(truePredicate), it works (but obviously breaks the intended behavior), so the closure'd inner expression can work, it just seems to lose its closure when we wrap it in t => expr.Invoke(t) then Expand() the outer expression.
Is there a way to make this work, either changing the implementation of ConditionalWhereExpression or the way I'm building the query lambda?
(Note that the implementation options of ConditionalWhereExpression are limited because EF Compiled Queries are restricted in what kinds of expression trees they support, in particular the logic we use in ConditionalWhere will not work, and you must pass a LambdaExpression to Where(), and not any other kind of Expression even if they would return an appropriate delegate upon evaluation.)
The text was updated successfully, but these errors were encountered:
(Apologies if this has been covered elsewhere, I wasn't able to find discussion of this case)
Context
We have an extension function to enable cleaner queries to support conditional logic in function chains, with a corresponding
[Expandable]
variant:The former works fine in regular EFCore usage, and the latter also works for their intended use case, EF Compiled Queries, in normal use cases where
truePredicate
does not reference outside values, for example:Problem
However, if the
truePredicate
does reference outside values then it fails, not just for EF Compiled Queries, but also just whenCompile()
ing theExpand()
ed lambda:We get this error:
Note that
Expand()
is required soEF.CompileAsyncQuery()
can translate the query logic, since it doesn't understandConditionalWhere
. Also if I alterConditionalWhereExpression
to just returnquery.Where(truePredicate)
, it works (but obviously breaks the intended behavior), so the closure'd inner expression can work, it just seems to lose its closure when we wrap it int => expr.Invoke(t)
thenExpand()
the outer expression.Is there a way to make this work, either changing the implementation of
ConditionalWhereExpression
or the way I'm building the query lambda?(Note that the implementation options of
ConditionalWhereExpression
are limited because EF Compiled Queries are restricted in what kinds of expression trees they support, in particular the logic we use inConditionalWhere
will not work, and you must pass aLambdaExpression
toWhere()
, and not any other kind ofExpression
even if they would return an appropriate delegate upon evaluation.)The text was updated successfully, but these errors were encountered: