Skip to content

A move into the default schema keeps the indexes and constraints on the table (#185) - #191

Merged
CaffeinatedCoder merged 1 commit into
release/5.xfrom
fix/185-default-schema-move
Oct 23, 2026
Merged

CaffeinatedCoder merged 1 commit into
release/5.xfrom
fix/185-default-schema-move

Conversation

@CaffeinatedCoder

Copy link
Copy Markdown
Owner

Closes #185

Into release/5.x. Closes acts only on main, so #185 is closed by hand after the merge.

Problem

Moving a table into the default schema (ToTable("bookings", "north") → ToTable("bookings")) dropped and re-created every complex index, exclusion constraint, temporal constraint and temporal foreign key on it. EF Core writes the target's schema into RenameTableOperation.NewSchema, so null means the default schema (MigrationsModelDiffer: NewSchema = target.Schema). The differs read null as "unchanged" (NewSchema ?? Schema), compared the source under its old schema, and matched nothing.

  • SQL Server: each index was rebuilt, although ALTER SCHEMA … TRANSFER keeps them.
  • PostgreSQL: the migration failed with 42P01. Npgsql 10 renders nothing for a move whose NewSchema is null (Generate(RenameTableOperation, …) checks NewSchema is not null), so the table stays in its schema. The creates then named a table in the default schema that doesn't exist.

Change

NewSchema is now read as EF Core writes it in the three places that build renamed-table identities: CustomMigrationsModelDiffer.GetDifferences, SourceColumnRenames (so #182's column-rename fix covers such a table too), and the Npgsql differ's BuildRenamedTables. The SQLite rebuild path already read it that way.

PostgreSQL stays on Npgsql's behaviour. The migration now runs, and the table stays in its old schema, as it does without this package. docs/upgrading.md says to name the schema (ToTable("bookings", "public")) to actually move it. Reporting that no-op to npgsql/efcore.pg is your call.

Also: a ### Changed answers row in all four changelogs, a docs/upgrading.md entry, CLAUDE.md, and ToTable added to DocumentationApiTests.ExternalApi.

Tests

  • SchemaMoveTests:
    • On PostgreSQL, moving into the default schema gives only the RenameTableOperation. The model has an exclusion constraint, a temporal constraint, and a temporal FK whose principal moves.
    • The same move plus a column rename gives only the rename operations.
    • Moves between named schemas, and out of the default schema, are unchanged.
    • The same check on SQL Server.
  • PostgresIntegrationTests.Move_into_default_schema_applies (PostgreSQL 18): the migration runs, and the index and exclusion constraint keep their OIDs.
  • SqlServerIntegrationTests.Move_into_default_schema_keeps_the_indexes (CI only): no index operations, and the index exists after the transfer.
  • With the source fix reverted: the three move-into-default unit tests and the PostgreSQL integration test fail (42P01: relation "sm_bookings" does not exist). The two moves that already worked pass either way, on purpose.
  • Suites: unit plus PostgreSQL 18/16, 716 passed.

🤖 Generated with Claude Code

… on the table

EF Core writes the target's schema into RenameTableOperation.NewSchema,
null for the default schema. The differs read null as "unchanged", so a
table moved into the default schema was compared under its old schema
and every complex index, exclusion constraint, temporal constraint and
temporal foreign key on it was dropped and created again. On SQL Server
that rebuilt each index although ALTER SCHEMA ... TRANSFER keeps them.
On PostgreSQL, where Npgsql 10 writes nothing for that move, the creates
named a table that was not there (42P01).

NewSchema is now read as EF Core writes it in the three places that
built renamed-table identities, as the SQLite rebuild path already did.

Closes #185

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CaffeinatedCoder CaffeinatedCoder added this to the 5.6.0 milestone Oct 23, 2026
@CaffeinatedCoder CaffeinatedCoder added bug Something isn't working severity/medium Inconsistency or failure in a narrow scenario package/core Affects EFCore.ComplexIndexes package/postgresql Affects EFCore.ComplexIndexes.PostgreSQL package/sqlserver Affects EFCore.ComplexIndexes.SqlServer area/indexes Complex-property, composite, unique and filtered indexes area/constraints Temporal (WITHOUT OVERLAPS, PERIOD) and exclusion constraints area/migrations The differs, snapshot format, EnsureCreated and design-time wiring labels Oct 23, 2026
@CaffeinatedCoder
CaffeinatedCoder merged commit 2edf10f into release/5.x Oct 23, 2026
13 of 14 checks passed
@CaffeinatedCoder
CaffeinatedCoder deleted the fix/185-default-schema-move branch October 23, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/constraints Temporal (WITHOUT OVERLAPS, PERIOD) and exclusion constraints area/indexes Complex-property, composite, unique and filtered indexes area/migrations The differs, snapshot format, EnsureCreated and design-time wiring bug Something isn't working package/core Affects EFCore.ComplexIndexes package/postgresql Affects EFCore.ComplexIndexes.PostgreSQL package/sqlserver Affects EFCore.ComplexIndexes.SqlServer severity/medium Inconsistency or failure in a narrow scenario

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant