Skip to content

Core differ on SQL Server scaffolds a NULLS-ordered or expression index that fails at apply; the core README says migrations add fails #172

Closed

Description

@CaffeinatedCoder

Found by a pre-release sweep of main @ eff80b4 (lens: docs-claims); reproduced in a scratch test. Not blocking the tag: the failure is loud. Moving the refusal to migrations add in a 5.5.x patch changes no applied answer, and it makes the packed README true.

Problem

The core package's packed README (src/EFCore.ComplexIndexes/README.md:98-100) says: "On SQL Server, and on providers without their own package such as SQLite, an index that uses [DbOrder.NullsFirst/NullsLast] makes dotnet ef migrations add fail."

On SQL Server, with the core differ, it doesn't fail there. ValidateRenderableParts returns early for any provider listed in Satellites (if (_satellite is not null) return;), and #150's ValidateNothingOnlyTheSatelliteRenders checks only options, constraints and the nullable-unique filter. So the migration scaffolds with the Npgsql sentinel column. database update then fails with an invalid column name that points at UseNpgsqlComplexIndexes(), not at the SQL Server package. The same applies to expression parts.

This happens in two cases:

  • A SQL Server consumer installs only the core package, which is who reads that README.
  • At runtime, UseComplexIndexes() is called in place of UseSqlServerComplexIndexes() (EnsureCreated, GenerateCreateScript).

With the SQL Server satellite's differ, it does fail at migrations add, so docs/sqlserver.md and the SQL Server README are right. The README sentence is older than #166; 934ec55 says the same.

Model

mb.Entity<NCommit>(b => b.HasComplexCompositeIndex(
    x => new { x.Created, Reviewed = DbOrder.NullsLast(x.ReviewedAt) }, indexName: "ix_commits_reviewed"));

MigrationHarness.Diff<CustomMigrationsModelDiffer>(sqlServerOptions, null, MigrationHarness.SqlServerModel<NCtx>()) scaffolds without an error, and renders:

CREATE INDEX [ix_commits_reviewed] ON [NCommit] ([Created], [ReviewedAt], [__requires_UseNpgsqlComplexIndexes__]);

Change

In the core differ, refuse NULLS-ordered and expression parts on a provider whose satellite isn't the one diffing. Do this in ValidateNothingOnlyTheSatelliteRenders, with the satellite's remedy (UseSqlServerComplexIndexes(), or reference EFCore.ComplexIndexes.SqlServer). On PostgreSQL the same refusal would replace an apply-time sentinel failure with a migrations add one. Rewording the README instead is the fallback.

Test

The model above through the core differ on SQL Server throws InvalidOperationException naming the SQL Server package. Add the same for an expression part, and for the core differ on Npgsql.

Activity

  1. added this to the 5.5.0 milestone on Oct 20, 2026
  2. added
    bugSomething isn't working
    severity/lowCosmetic, message or documentation-level difference
    package/coreAffects EFCore.ComplexIndexes
    package/sqlserverAffects EFCore.ComplexIndexes.SqlServer
    area/indexesComplex-property, composite, unique and filtered indexes
    area/migrationsThe differs, snapshot format, EnsureCreated and design-time wiring
    on Oct 20, 2026
  3. added 2 commits that reference 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/indexesComplex-property, composite, unique and filtered indexesarea/migrationsThe differs, snapshot format, EnsureCreated and design-time wiringbugSomething isn't workingpackage/coreAffects EFCore.ComplexIndexespackage/sqlserverAffects EFCore.ComplexIndexes.SqlServerseverity/lowCosmetic, message or documentation-level difference

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions