Skip to content

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