-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Description
Our precompiled query feature (for supporting NativeAOT) involves intercepting query LINQ operators. The terminating query operator is replaced with an implementation that actually executes the query, while intermediate operators are basically no-ops, simply propagating the root DbContext forward to the terminating operator.
However, if an operator accepts a lambda, that lambda can capture variables; this is how query parameters are expressed in EF queries:
var name = "foo";
var blogs = await context.Blogs.Where(b => b.Name == name).ToListAsync();In these cases, the interceptor for Where() must be capable of extracting the captured variable's value (which will be different each time the query is executed), and passing it as a query parameter. This means that we need to be able to inspect a LINQ expression tree (the lambda argument to Where), identify evaluatable fragments, and generate interceptor code that will extract those fragments when such a tree is given.
We'll modify the ParameterExtractingExpressionVisitor to have an additional mode, which is used at publish-time when generating query interceptors. This should use the same logic as the regular query execution path, but instead of actually extracting parameters (which are irrelevant at this point), the visitor will produce a tree of paths to all evaluatable fragments. The query precompilation can then take this tree and generate interceptor code based on it which will drill into the given tree, evaluate the relevant fragments and store the results as query parameters in our QueryContext.
As this is quite a change for ParameterExtractingExpressionVisitor, we may as well also optimize it (#32698).