Skip to content

Fix DefaultIfEmpty lifting logic within SelectMany #36248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 23, 2025

Conversation

roji
Copy link
Member

@roji roji commented Jun 15, 2025

This fixes the logic which lifts DefaultIfEmpty within the SelectMany collection selector; this optimization causes context.Blogs.SelectMany(b => b.Posts.DefaultIfEmpty() to be translated as a simple LEFT JOIN, instead of having a subquery with the complex DefaultIfEmpty logic.

The previous logic erroneously identified any DefaultIfEmpty anywhere within the SelectMany selector, and lifted it out (translating the SelectMany as LEFT JOIN/OUTER APPLY) in cases which caused incorrect data to be returned:

  1. If the DIE is nested within another operator nested in the SelectMany selector, it cannot be lifted out (context.Blogs.SelectMany(b => b.Posts.SelectMany(p => p.Comments.DefaultIfEmpty()). This is #33343.
  2. If the DIE appears before another LINQ operator which changes the resultset in non-trivial ways, it also cannot be lifted (e.g. blogs.SelectMany(b => b.Posts.DefaultIfEmpty().Where(p => p.Id > 3))).

We now have state tracking whether DefaultIfEmpty can be lifted as CorrelationFindingExpressionVisitor visits the SelectMany selector.

Fixes #33343
Fixes #19095

@roji roji force-pushed the NestedDefaultIfEmpty branch from e0575d8 to 7ba83c8 Compare June 15, 2025 21:46
@roji roji marked this pull request as ready for review June 15, 2025 21:46
@roji roji requested a review from a team as a code owner June 15, 2025 21:46
@roji roji enabled auto-merge (squash) June 15, 2025 21:47
@roji roji force-pushed the NestedDefaultIfEmpty branch 2 times, most recently from 82ff17b to 6020ae1 Compare June 15, 2025 21:48
@roji roji force-pushed the NestedDefaultIfEmpty branch from 6020ae1 to e57a700 Compare June 16, 2025 20:44
@roji roji merged commit 2c27fcd into dotnet:main Jun 23, 2025
7 checks passed
@roji roji deleted the NestedDefaultIfEmpty branch June 23, 2025 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants