[release/11.0] Translate set operations over null-checked subqueries - #38847
Open
AndriySvyryd wants to merge 4 commits into
Open
[release/11.0] Translate set operations over null-checked subqueries#38847AndriySvyryd wants to merge 4 commits into
AndriySvyryd wants to merge 4 commits into
Conversation
- Retry server projection binding after lowering single-result subqueries - Simplify null checks over non-entity nullability markers - Add SQL Server and SQLite regression coverage Fixes dotnet#38838 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Allow opting out of projection retry and marker-null simplification Fixes dotnet#38838 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes an EF Core 11.0 regression where relational set operations (e.g. Concat/Union) fail to translate when a projection contains a null-checked, to-one, non-entity subquery referenced multiple times. The change is implemented in relational projection binding so that marker-backed object null comparisons become marker null tests, and server-side projection binding is retried after lowering single-result subqueries—allowing set operations to compose when the final projection is fully SQL-translatable.
Changes:
- Update relational projection binding to (1) rewrite
== null/!= nullover marker-gated non-entity projections to marker null tests, and (2) retry member-based projection binding after single-result subquery lowering (with a fallback to the original client-projection path). - Add/adjust relational specification tests to cover the regression shape (Issue #38838) and validate set-operation translation over these projections.
- Update SQL Server/SQLite functional test baselines to assert the newly translated SQL for the affected scenarios.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs | Implements the translation fix: simplifies marker-gated object null comparisons and retries member-based binding after lowering single-result subqueries (with opt-out switch). |
| test/EFCore.Relational.Specification.Tests/Query/NorthwindSetOperationsQueryRelationalTestBase.cs | Adds regression coverage for set operations over null-checked to-one non-entity subqueries (Concat + Union). |
| test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs | Updates the union-of-two-leftjoin-nonentity scenario to assert results now that translation is expected to succeed. |
| test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSetOperationsQuerySqlServerTest.cs | Adds SQL baseline assertions for the new Northwind regression test on SQL Server. |
| test/EFCore.Sqlite.FunctionalTests/Query/NorthwindSetOperationsQuerySqliteTest.cs | Adds SQL baseline assertions for the new Northwind regression test on SQLite. |
| test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs | Adds SQL baseline assertions for the ad-hoc union translation scenario on SQL Server. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Retry lowered client projections only for set-operation operands and simplify the synthetic nullability-marker check before rebinding. This preserves ordinary client evaluation while allowing the regression query to translate. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 618bf8ca-f46b-4556-9c19-2cdb4e954c9a
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment on lines
+53
to
+57
| private sealed class MarkerNullCheckSimplifyingExpressionVisitor : ExpressionVisitor | ||
| { | ||
| protected override Expression VisitBinary(BinaryExpression node) | ||
| { | ||
| if (node is { NodeType: ExpressionType.Equal or ExpressionType.NotEqual, Method: null } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #38838
This is part of the broader work tracked by #30915.
Description
PR #38479 introduced nullability markers for non-entity projections. When a to-one non-entity subquery was referenced multiple times and compared to null, its marker check remained in the client projection. Relational set operations then rejected the query even though all final values were SQL-translatable.
This change retries server projection binding only when a set-operation operand still has client projections after single-result subqueries have been lowered. A retry-only preprocessing step simplifies synthetic marker-backed object null comparisons into marker null checks so the operand can be rebound to SQL. If complete translation still fails, the original client projection remains and existing rejection behavior is preserved.
Customer impact
Queries shaped like the following throw instead of translating on 11.0 preview 7:
A workaround exists by projecting a required property as nullable and checking that property instead of the object, but it is non-obvious and requires restructuring the projection.
How found
User reported on 11.0 preview 7. The issue has one reporter, two comment authors, and one reaction.
Regression
This regressed between 11.0 preview 6 and preview 7 and was introduced by PR #38479.
Testing
The regression and related client-projection scenarios are covered across SQL Server and SQLite. The complete solution test suite was run locally; assemblies affected by transient parallel SQL database creation races were rerun sequentially and passed.
Risk
Low. The retry is scoped to relational set-operation operands that still contain client projections, leaving ordinary client projection behavior unchanged. Quirk added:
Microsoft.EntityFrameworkCore.Issue38838.