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
{{ message }}
Repository navigation
Query: Re-evaluate concept of pending selector in nav expansion #20291
When we rewrote query in 3.0, we added a concept called pending selector in nav expansion. Since nav expansion is expanding navigations, we defer applying the projection and keep intermediate shape to reuse the navigations already expanded. This is useful in many scenarios but deferring projection has side effects. See #7776 for one example. That is just one scenario. Any time FirstOrDefault is used in any way (selectmany or next select), by deferring that projection we duplicate the subquery for any property access on that. Not only it causes ugly query but potentially bad perf.
Instead of deferring the projection if we applied projection in above case then, during translation it would cause a subquery and any further property access would be columns coming out subquery. Hence it can be translated without causing client eval error at the same time avoid repeating subquery. This approach would do exactly what @maumar requested in the #7776 (comment)
Making this work will require
Update navigation expansion to take a hybrid approach to apply projection at the same time remember the navigations already expanded to reuse them.
We only need to remember navigations which can be accessible by projection being applied.
Update translation pipeline to handle translating query operators after client eval phase if it can be server evaluated.
There are few more associated issues this would fix. #18775
Reacted by Makla, GLuca74, Vadim Ovchinnikov, GhalamborM, Steven Darby, Vinicius Chiele, Иван Бажанов, jogaiii and Victor Irzak
More narrowly remove the pending selector feature; in other words, stop moving the Select() operator forward. As written above, we'd need to replace this with logic to ensure that expanded navigations are reused, etc. This is the smaller version of the change.
More broadly remove navigation expansion altogether as a universal preprocessing step, and introduce joins as part of the translation phase instead. This is a bigger change that's tracked by #32957.
Note that whatever approach we choose here, this will most likely be a breaking change: since we currently move forward projections, it's possible to have a client-evaluated Select() in the middle of the query:
_=awaitcontext.Blogs.Select(b =>LocalFunction()).Where(...).ToListAsync();// Nav expansion converts this to context.Blogs.Where(...).Select(b => LocalFunction()).ToListAsync()
Such queries would no longer translate, and users would have to manually rewrite them to put the Select at the end. IMHO this is a good breaking change, as it simplifies the rules as to where we allow client evaluation (last Select only), and make it much clearer which queries perform client eval and where.
Activity
Query: Perform join operations when one of the source has client eval
Query: Perform join operations when one of the source has client eval
Query: Perform join operations when one of the source has client eval
Query: Perform join operations when one of the source has client eval
12 remaining items
roji commentedon Jun 24, 2025
Issues likely caused by this, which we should verify once this is done:
roji commentedon Jun 24, 2025
There are two possible approaches here:
Note that whatever approach we choose here, this will most likely be a breaking change: since we currently move forward projections, it's possible to have a client-evaluated Select() in the middle of the query:
Such queries would no longer translate, and users would have to manually rewrite them to put the Select at the end. IMHO this is a good breaking change, as it simplifies the rules as to where we allow client evaluation (last Select only), and make it much clearer which queries perform client eval and where.
Make AsSubQuery public as an experimental API (#44)