Don't transform Cosmos query to ReadItem when WithPartitionKey conflicts with predicate partition key#38439
Open
Copilot wants to merge 8 commits into
Open
Don't transform Cosmos query to ReadItem when WithPartitionKey conflicts with predicate partition key#38439Copilot wants to merge 8 commits into
Copilot wants to merge 8 commits into
Conversation
…icate partition key Fixes #38238 Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix conflicting partition key filter in ReadItem case
Don't transform Cosmos query to ReadItem when WithPartitionKey conflicts with predicate partition key
Jun 17, 2026
There was a problem hiding this comment.
Pull request overview
This PR fixes an incorrect Cosmos optimization where a query could be transformed into a ReadItem call even when WithPartitionKey(...) conflicts with partition-key comparisons in the predicate—causing the predicate partition-key to be silently ignored and returning the wrong document. The change prevents the ReadItem transform in that scenario so the query executes normally and conflicting values correctly yield zero results.
Changes:
- Update
CosmosReadItemAndPartitionKeysExtractorto skip theReadItemtransform when partition key values come fromWithPartitionKey()and the predicate also contains partition key comparison(s). - Add new functional tests for the conflicting
WithPartitionKey+(id && partitionKey)predicate case (including leaf/inheritance variants). - Update multiple Cosmos functional test SQL baselines to reflect the new (non-
ReadItem) query shape in same-value scenarios.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/EFCore.Cosmos/Query/Internal/CosmosReadItemAndPartitionKeysExtractor.cs | Adds a predicate-partition-key-comparison flag and blocks ReadItem transform when WithPartitionKey() may conflict with predicate PK comparisons. |
| test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTestBase.cs | Adds a new base test covering conflicting WithPartitionKey + predicate partition-key comparison. |
| test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryInheritanceTestBase.cs | Adds a leaf/inheritance variant of the conflicting-case test. |
| test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryTest.cs | Updates baselines to expect regular query SQL (not ReadItem) and adds baseline for the new conflicting-case test. |
| test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryRootDiscriminatorInIdTest.cs | Updates baselines for non-ReadItem query shape and adds baselines for the new conflicting-case tests. |
| test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryNoDiscriminatorInIdTest.cs | Updates baselines for non-ReadItem query shape and adds baselines for the new conflicting-case tests. |
| test/EFCore.Cosmos.FunctionalTests/Query/ReadItemPartitionKeyQueryDiscriminatorInIdTest.cs | Updates baselines for non-ReadItem query shape and adds baselines for the new conflicting-case tests. |
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…ng LINQ + ApplyTypeMapping Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…titionKey + same predicate When a literal is passed to WithPartitionKey() it gets funcletized to a SqlParameterExpression (outside a lambda), while the same literal in a Where() stays as a SqlConstantExpression. SqlExpression.Equals() returned false for different subtypes even with identical values, so the conflict detection incorrectly disabled ReadItem for same-value cases. Fix: when withPkValue is a parameter and predicateValue is a constant, and all partition key properties are encoded in the JSON ID, ReadItem is safe regardless of runtime value — a wrong partition key returns null rather than the wrong document. Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
6 tasks
…oop, shorten comments Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
cincuranet
approved these changes
Jun 19, 2026
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 #38238
Combining
WithPartitionKey(...)with a predicate that also compares the partition key produced aReadItemusing theWithPartitionKeyvalue, silently discarding the predicate. A conflicting value returned theWithPartitionKeydocument instead of zero results.Changes
CosmosReadItemAndPartitionKeysExtractor: skip the ReadItem transform only when partition key values supplied viaWithPartitionKey()actually conflict with partition key comparisons in the predicate. Matching values remain eligible forReadItem, while conflicting values execute as a regular query so the predicate is preserved and yields zero results.ReadItemeligibility.predicateValue.TypeMappingto theWithPartitionKey()value before comparing (sinceWithPartitionKey()arguments are translated withapplyDefaultTypeMapping:false), ensuring identical constant/parameter pairs are correctly recognized as non-conflicting. A special case handles theSqlParameterExpressionvsSqlConstantExpressionmismatch that arises when a literal is passed toWithPartitionKey()(funcletized to a parameter) but written inline in the predicate (stays a constant): when all partition key properties are also part of the JSON ID, ReadItem is safe regardless.Behavior change
WithPartitionKey()and an equivalent predicate partition-key comparison (same values) continue to translate toReadItem.WithPartitionKey()and conflicting predicate partition-key comparisons no longer translate toReadItem; they execute as regular queries so the conflict is honored and no result is returned.WithPartitionKey(pkVar)andPartitionKey == differentPkVarwhere both are different local variables holding the same runtime value cannot be recognized as equal at translate time and fall through to a full query (the result is still correct).Tests
WithPartitionKey_and_predicate_with_id_and_conflicting_partition_key(+_leafvariant) covering the conflicting case (asserts empty).WithPartitionKey_and_predicate_with_id_two_locals_same_valuedocumenting the behavior whenWithPartitionKeyand the predicate use two different local variables that happen to hold the same value — these cannot be recognized as equal at translate time, so the query falls through to a full SQL query (result is still correct).