EFCore.ComplexIndexes.SqlServer 5.5.0

dotnet add package EFCore.ComplexIndexes.SqlServer --version 5.5.0
                    
NuGet\Install-Package EFCore.ComplexIndexes.SqlServer -Version 5.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EFCore.ComplexIndexes.SqlServer" Version="5.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EFCore.ComplexIndexes.SqlServer" Version="5.5.0" />
                    
Directory.Packages.props
<PackageReference Include="EFCore.ComplexIndexes.SqlServer" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EFCore.ComplexIndexes.SqlServer --version 5.5.0
                    
#r "nuget: EFCore.ComplexIndexes.SqlServer, 5.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EFCore.ComplexIndexes.SqlServer@5.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EFCore.ComplexIndexes.SqlServer&version=5.5.0
                    
Install as a Cake Addin
#tool nuget:?package=EFCore.ComplexIndexes.SqlServer&version=5.5.0
                    
Install as a Cake Tool

EFCore.ComplexIndexes.SqlServer

On EF Core 11 or later? This package supports EF Core 10 only. From 5.5.0 it throws when you register it on any other major version. Its successor for EF Core 11 is a new package, CodoMetis.EFCore.SchemaKit, tracked in #37.

SQL Server index options for EFCore.ComplexIndexes. This package brings the core package with it.

You get SQL Server's index options on indexes over complex properties:

  • Clustered / nonclustered control
  • Covering indexes (INCLUDE)
  • Online index builds (ONLINE = ON)
  • Fill factor
  • Sort in tempdb
  • Data compression (ROW / PAGE)

Setup

Migrations need no setup. Every option goes into the migration as a SQL Server annotation that EF Core's own SQL Server generator writes. Install the package, declare your indexes, and run dotnet ef migrations add.

There is one optional call. Database.EnsureCreated(), GenerateCreateScript() and the pending-model-changes check in Migrate() use your context's own services, which the automatic design-time registration never reaches. Without a registration, EnsureCreated() creates the tables and none of the indexes, with no error. Register the package once so these see your complex indexes too:

options.UseSqlServer(connectionString).UseSqlServerComplexIndexes();

If you build your own internal service provider, call AddSqlServerComplexIndexes() on your IServiceCollection instead.

Usage

builder.ComplexProperty(x => x.Email, c =>
    c.Property(x => x.Value).HasColumnName("email"));

builder.HasComplexIndex(x => x.Email.Value, ix => ix
    .IsUnique()
    .HasName("ux_person_email")
    .IncludeProperties("Name")     // property paths resolve to columns
    .IsCreatedOnline()             // ONLINE = ON
    .HasFillFactor(80));
// CREATE UNIQUE INDEX [ux_person_email] ON [person] ([email])
//   INCLUDE ([name]) WITH (FILLFACTOR = 80, ONLINE = ON);

The builder also has IsClustered(), SortInTempDb() and UseDataCompression(DataCompressionType.Page).

Filtered indexes (filter:) and DbOrder.Desc need nothing from this package, because EF Core's own index operation carries both.

A filter can name properties instead of columns: migrations add turns filter: "{DeletedAt} IS NULL" into [deleted_at] IS NULL.

Deliberate rejections

If you declare something SQL Server can't express, dotnet ef migrations add fails and names the problem, instead of writing a migration that would fail when it runs:

  • Expression parts. SQL Server has no DDL for an index on an expression. Store the expression in a persisted computed column and index that column instead.
  • DbOrder.NullsFirst / NullsLast. T-SQL has no NULLS FIRST/NULLS LAST.
  • A clustered index with INCLUDE columns. Included columns belong to nonclustered indexes. A clustered index already stores every column.
  • A clustered filtered index. A filtered index must be nonclustered.
  • A second clustered index on a table. Usually the primary key already holds the clustered slot: SQL Server clusters the primary key unless you declare HasKey(...).IsClustered(false). So that is normally what a clustered complex index collides with.

Documentation

Changelog

This package's changelog, or the root changelog covering all three packages.

MIT licensed.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.5.0 53 10/20/2026
5.4.1 1,511 9/22/2026
5.4.0 223 9/22/2026
5.3.0 138 9/5/2026
5.2.0 151 9/5/2026
5.1.0 126 9/5/2026
5.0.3 222 8/15/2026
5.0.2 135 8/15/2026
5.0.1 119 8/10/2026
5.0.0 125 8/10/2026

The last 5.x minor with a change of its own: the line refuses EF Core 11, whose successor is CodoMetis.EFCore.SchemaKit.SqlServer.

Changed answers

- Indexes: a unique complex index over nullable columns gets EF Core's IS NOT NULL filter, so rows without a value no longer collide. It admitted one such row and refused the second (#88 (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/issues/88), Upgrading (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/docs/upgrading.md#unique-indexes-over-nullable-columns-on-sql-server)).
- Indexes: an IncludeProperties(…) entry that names neither a property nor a column of the table fails at migrations add. When its property was removed, the migration dropped only the column, and failed at apply with Msg 5074 (#142 (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/issues/142), Upgrading (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/docs/upgrading.md#include-entries-must-name-a-column)).

Breaking

- Registration: UseSqlServerComplexIndexes(), AddSqlServerComplexIndexes() and the design-time registration dotnet ef runs throw InvalidOperationException on an EF Core major other than 10, naming CodoMetis.EFCore.SchemaKit for EF Core 11. EF Core 10 on .NET 11 keeps working (Upgrading (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/docs/upgrading.md#ef-core-11-is-refused-at-registration)).
- Indexes: on a database with a case-sensitive collation, complex index names that differ only in case fail at migrations add; rename one (Upgrading (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/docs/upgrading.md#rename-complex-index-names-that-differ-only-in-case)).

Changed

- Packaging: each package carries the version's section of its changelog as its NuGet release notes, which nuget.org's Release Notes tab and Visual Studio's Updates tab show.
- Packaging: the release notes, the README on nuget.org and the GitHub release link the documentation at the version's tag, so they keep describing the version they shipped with after main moves on to the next line.
- Packaging: the PostgreSQL and SQL Server packages depend on exactly their own version of EFCore.ComplexIndexes, and the core differ refuses a satellite of another version, naming both. Update the packages together: a 5.4.x satellite beside core 5.5.0 was refused as the core differ (#169 (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/issues/169)).

Fixed

- Indexes: a clustered complex index added in a later migration beside an existing one, and a complex index named like its table's primary key or a unique constraint, fail at migrations add, where they failed at apply (SQL Server (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/docs/sqlserver.md#deliberate-rejections)).
- Indexes: complex index names that differ only in case, from each other or from a native index, fail at migrations add, where they failed at apply because the default collation compares them without regard to case (Index names (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/README.md#single-column-index-on-a-complex-property)).
- Migrations: a complex index renamed away from a name that the same migration gives to another index applies, where it failed at apply because the renamed index still held the name. It is dropped before EF Core's operations and created after them (Index names (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/README.md#single-column-index-on-a-complex-property)).
- Migrations: changing the type, length or nullability of a column a complex index reads applies, an index renamed in the same migration included, where it failed with Msg 5074. The index is dropped before the ALTER COLUMN and created after it (SQL Server (https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/docs/sqlserver.md)).

Full changelog: https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes/blob/v5.5.0/src/EFCore.ComplexIndexes.SqlServer/CHANGELOG.md