[release/11.0] Fix JSON indexes for SQLite - #39089
AndriySvyryd with Copilot wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Fixed collection-element indexes still target the entire JSON container instead of the selected element.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds query-compatible SQLite expression indexes for JSON-mapped members and validates unsupported wildcard paths.
Changes:
- Generates SQLite JSON extraction expressions for indexes.
- Resolves JSON metadata from migration target models.
- Rejects wildcard collection indexes and adds coverage.
| File | Description |
|---|---|
src/EFCore.Design/Migrations/Design/CSharpMigrationOperationGenerator.cs |
Omits model-bound JSON annotations. |
src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs |
Resolves JSON indexes from target models. |
src/EFCore.Sqlite.Core/Infrastructure/Internal/SqliteModelValidator.cs |
Rejects wildcard array indexes. |
src/EFCore.Sqlite.Core/Migrations/SqliteMigrationsSqlGenerator.cs |
Generates SQLite JSON index expressions. |
src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs |
Exposes the validation message. |
src/EFCore.Sqlite.Core/Properties/SqliteStrings.resx |
Defines the validation message. |
test/EFCore.Sqlite.FunctionalTests/Migrations/SqliteMigrationsSqlGeneratorTest.cs |
Tests JSON index migration SQL. |
test/EFCore.Sqlite.Tests/Infrastructure/SqliteModelValidatorTest.cs |
Tests wildcard rejection. |
Files not reviewed (1)
- src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs: Generated file
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
…for SQLite The new SqliteModelValidator.ValidateIndex rejection of 'all array elements' JSON indexes was not reflected in the shared RelationalModelValidatorTest cases inherited by SqliteModelValidatorTest, causing 4 previously-passing tests to fail with the new SQLite-specific exception instead of their expected outcome. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Append the final array segment when a JSON index targets a fixed element of a collection property. Use SQLite's numeric right operand for a root array element and a JSON path for nested collection leaves. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
3867d27 to
df9afa1
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Scaffolded operations lose essential JSON-path metadata and can silently generate an index over the container when no matching target model is available.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
Resolved since last review (1)
Files not reviewed (1)
- src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs: Generated file
Record the JSON index SQL generator override. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…migrations Mirrors the existing SQLite Create_unique_json_index_over_complex_property_member test: verifies that CSharpMigrationOperationGenerator omits the non-literal RelationalJsonIndex annotation from scaffolded migration code, and that removing this filter causes CSharpHelper.UnknownLiteral to throw. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Detects_index_on_complex_collection_property already covers indexing all elements of a JSON collection and asserts the same JsonIndexAllElementsNotSupported error. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Composite JSON indexes with mixed sort directions cannot be scaffolded because deduplicated columns and per-member sort metadata have different lengths.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Resolved since last review (1)
Files not reviewed (1)
- src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs: Generated file
A composite JSON index whose members share one deduplicated container column could not represent mixed sort directions: GetIndexColumns deduplicates JSON members to a single operation column, while ITableIndex.IsDescending still carried one entry per JSON member, causing CreateIndexOperation.CreateFrom to throw when the lengths didn't match. RelationalJsonIndex now tracks IsDescending per JSON element (with an IsElementDescending helper honoring the existing empty-list-means-all shorthand). TableIndex.IsDescending is null whenever the mapped index is a JSON index, since no database supports mixing a plain column and its contained JSON members in a single index, and the per-element sort order can no longer be represented at the column level. SQLite's GenerateIndexColumnList reads sort order from the RelationalJsonIndex element list instead of operation.IsDescending.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The constructor change breaks binary compatibility, and the new equality/hash behavior lacks focused coverage.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
Resolved since last review (1)
Files not reviewed (2)
- src/EFCore.Relational/Properties/RelationalStrings.Designer.cs: Generated file
- src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs: Generated file
| public RelationalJsonIndex( | ||
| IReadOnlyList<IRelationalJsonElement> elements, | ||
| IReadOnlyList<IReadOnlyList<int?>?>? collectionIndices) | ||
| IReadOnlyList<IReadOnlyList<int?>?>? collectionIndices, | ||
| IReadOnlyList<bool>? isDescending = null) |
| || (CollectionIndices is null) != (other.CollectionIndices is null) | ||
| || (IsDescending is null) != (other.IsDescending is null)) |


Fixes #39064
Description
EF Core 11 supports indexes over members of complex properties, including complex properties stored as JSON. On SQLite, migrations generated these indexes over the entire JSON container column instead of the configured member. This change generates a SQLite expression index using the same
->>expression produced by query translation, preserves JSON index paths when migrations are scaffolded, handles fixed collection elements, and rejects wildcard array indexes that SQLite cannot represent as a usable scalar expression index.Customer impact
Unique indexes configured over JSON members do not enforce uniqueness for that member, and ordinary indexes cannot be used by matching queries. This can allow duplicate values that the model declares unique, although it does not corrupt existing stored JSON values.
How found
User reported on EF Core 11.0.0-rc1.
Regression
No, indexes over complex-property members are a new EF Core 11 feature.
Testing
Added or modified 8 tests covering SQLite JSON SQL generation, root and nested fixed collection elements, unsupported wildcard collection indexes, migration annotation handling, and provider-specific model validation.
Risk
Low. The changes are scoped to SQLite migration handling for JSON indexes.