Skip to content

A temporal foreign key's TPC copy on a long derived table is not shortened, and a 5.4.1 model fails at the first migrations add #168

Closed

Description

@CaffeinatedCoder

Found by a pre-release sweep of main @ eff80b4 (lenses: round-trip, sibling-parity); reproduced in a scratch test. Decide before the tag: either shorten the copy or document the refusal. Shortening it later changes the answer for models that work around it.

Problem

#145 shortens the default name of a TPC copy that runs past the identifier limit for complex indexes, exclusion constraints and temporal constraints, but not for temporal foreign keys. In ApplyTemporalConstraints (NpgsqlComplexIndexMigrationsModelDiffer.cs:697-698), the FK calls ThrowIfIdentifierTooLong(…, foreignKey.DependentTable, "name") without the copy's Origin, and foreign keys have no ShortenConstraintCopyNames pass. Exclusion constraints have one at :1191 and temporal constraints at :1331. Commit f4986ed says this was on purpose ("Every other default name keeps the 5.2.0 refusal").

docs/upgrading.md says otherwise. The TPC entry covers "a complex index, exclusion constraint, temporal constraint or temporal foreign key" and says a copy name past the limit "is shortened as EF Core shortens its own". Its list of what "fail[s] at migrations add now" doesn't include this case. A 5.4.1 model that put the FK on the base table only now fails at the first migrations add after the upgrade, with no model change.

Model

mb.Entity<FkRoom>(b => { b.ToTable("rooms"); b.HasTemporalConstraint(x => x.RoomId, x => x.Available); });
mb.Entity<FkBooking>(b =>
{
    b.UseTpcMappingStrategy();
    b.ToTable("bookings");
    b.HasTemporalForeignKey<FkBooking, FkRoom>(x => x.RoomId, x => x.During, x => x.RoomId, x => x.Available);
});
mb.Entity<FkCorpBooking>().ToTable("corporate_bookings_for_customer_accounts_region_xyz");

MigrationHarness.NpgsqlDiff(null, model) on eff80b4 throws:

InvalidOperationException: The temporal foreign key name 'FK_corporate_bookings_for_customer_accounts_region_xyz_rooms_RoomId_During' on table 'corporate_bookings_for_customer_accounts_region_xyz' is 74 bytes long, but the provider allows at most 63. … Give the declaration an explicit, shorter name

The advice works: FK names are unique per table, and with name: "fk_booking_room" the whole upgrade applied on PostgreSQL 18 (23503 on the derived table). The failure is loud, and a workaround exists.

Change

Pick one before the tag:

  • Pass foreignKey.Origin and shorten FK copies per table, among the table's constraints, as the other kinds are shortened.
  • Keep the refusal, name the case in the upgrade guide's "fail at migrations add now" list, and say in the message that the long name comes from the TPC copy.

Test

For the model above: NpgsqlDiff(null, model) succeeds with a FK_…~ name on the derived table, or the guide lists the refusal and a test pins the message.

Activity

  1. added this to the 5.5.0 milestone on Oct 20, 2026
  2. added
    bugSomething isn't working
    breakingChanges an answer or a signature — needs a major
    severity/mediumInconsistency or failure in a narrow scenario
    package/postgresqlAffects EFCore.ComplexIndexes.PostgreSQL
    area/constraintsTemporal (WITHOUT OVERLAPS, PERIOD) and exclusion constraints
    area/migrationsThe differs, snapshot format, EnsureCreated and design-time wiring
    on Oct 20, 2026
  3. CaffeinatedCoder commented on Oct 20, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Decided in #176: the first option. A temporal foreign key's default-named copy past the limit is shortened among its table's constraints (FK_…~), on both diff sides. A 5.4.1 snapshot upgrade adds the copies, and on PostgreSQL 18 the long table rejects with 23503 under the shortened name.

  4. added a commit that references this issue on Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/constraintsTemporal (WITHOUT OVERLAPS, PERIOD) and exclusion constraintsarea/migrationsThe differs, snapshot format, EnsureCreated and design-time wiringbreakingChanges an answer or a signature — needs a majorbugSomething isn't workingpackage/postgresqlAffects EFCore.ComplexIndexes.PostgreSQLseverity/mediumInconsistency or failure in a narrow scenario

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions