EFCore.ComplexIndexes 5.3.0

dotnet add package EFCore.ComplexIndexes --version 5.3.0
                    
NuGet\Install-Package EFCore.ComplexIndexes -Version 5.3.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" Version="5.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EFCore.ComplexIndexes" Version="5.3.0" />
                    
Directory.Packages.props
<PackageReference Include="EFCore.ComplexIndexes" />
                    
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 --version 5.3.0
                    
#r "nuget: EFCore.ComplexIndexes, 5.3.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@5.3.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&version=5.3.0
                    
Install as a Cake Addin
#tool nuget:?package=EFCore.ComplexIndexes&version=5.3.0
                    
Install as a Cake Tool

EFCore.ComplexIndexes

Index support for complex type properties in EF Core migrations — the missing piece for value object-driven architectures.

EF Core models complex properties (value objects) but its migration tooling does not generate indexes for their nested columns. This package hooks into EF Core's design-time pipeline and emits the CREATE INDEX / DROP INDEX operations for you.

This is the core, provider-agnostic package. It works with any EF Core relational provider. For provider-specific index features, add a satellite package — each one includes this package automatically:

Package Adds
EFCore.ComplexIndexes.PostgreSQL GIN/GiST/BRIN/SP-GiST/Hash methods, operator classes, INCLUDE, NULLS FIRST/LAST, expression & JSON indexes, temporal and exclusion constraints
EFCore.ComplexIndexes.SqlServer Clustered, covering (INCLUDE), online builds, fill factor, sort-in-tempdb, data compression

Setup

None. The migration differ is registered through EF Core's design-time tooling automatically — install the package, declare your indexes in OnModelCreating, and run dotnet ef migrations add.

Usage

Single-column index on a complex property

builder.ComplexProperty(x => x.EmailAddress, c =>
    c.Property(x => x.Value)
     .HasComplexIndex(isUnique: true, filter: "deleted_at IS NULL")
);

Column names are resolved against the real model, so both convention-based names (Origin_Source) and explicit HasColumnName overrides are honored.

A filter may name properties instead of columns — filter: "{DeletedAt} IS NULL" resolves to the mapped column at migrations add, quoted for the provider, and is baked into the migration. A selector reaches into complex properties and, for a value object mapped through a converter, one step further: x => x.Email.Value resolves to the converted column.

Several indexes over one column

A property-level declaration holds one index per property. To give a column several differently-filtered indexes (the classic soft-delete pattern), declare them at the entity level — the selector reaches into complex properties, and each index needs its own explicit name:

builder.HasComplexIndex(x => x.EmailAddress.Value,
    isUnique: true, filter: "deleted_at IS NULL", indexName: "ux_person_email_active");
builder.HasComplexIndex(x => x.EmailAddress.Value,
    indexName: "ix_person_email_all");

Index names must be unique per table and within the provider's identifier limit (63 bytes on PostgreSQL, which would otherwise truncate silently), and the package enforces both at dotnet ef migrations add rather than letting the database reject — or quietly shorten — the name.

Composite index across scalar and nested properties

builder.HasComplexCompositeIndex(
    x => new { x.Name, x.EmailAddress.Value },
    isUnique: true);

Per-column sort direction

builder.HasComplexCompositeIndex(
    c => new { c.Created, Counter = DbOrder.Desc(c.Version.Counter) },
    indexName: "ix_commits_created_counter");
// CREATE INDEX ix_commits_created_counter ON ... (created, counter DESC);

Direction maps onto EF Core's native CreateIndexOperation.IsDescending, so every relational provider renders it. Because a wrapped member is a method call, C# requires you to name it in the anonymous type.

DbOrder.NullsFirst/NullsLast are declared here too, but rendering them is provider-specific — see the PostgreSQL package.


Reading declarations back

GetComplexIndexes() on an entity type (or the model) returns every declaration — property-level, entity-level, composite, expression — with its parts, IsUnique, Filter and explicit Name, so an application can check its own conventions; FindComplexIndex(name) looks one up by explicit name. It works on the mutable model inside OnModelCreating too, and the differ reads declarations through the same code.

var unfiltered = modelBuilder.Model.GetEntityTypes()
    .SelectMany(e => e.GetComplexIndexes())
    .Where(ix => ix.IsUnique && ix.Filter is null);

Or install the convention: on the mutable model, AddComplexIndexFilter(predicate, where) ANDs a predicate onto every selected declaration's filter, idempotently, and AddComplexIndex(definition) adds one with the fluent API's identity rules. Both amend what is declared at the time of the call, so run them after the configurations.

Documentation

Full documentation, including every provider-specific feature: https://github.com/CaffeinatedCoder/EFCore.ComplexIndexes

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 (4)

Showing the top 4 NuGet packages that depend on EFCore.ComplexIndexes:

Package Downloads
SIL.Harmony

CRDT application library for building offline-first apps with Entity Framework Core.

SIL.Harmony.Linq2db

linq2db integration for the Harmony CRDT library.

EFCore.ComplexIndexes.PostgreSQL

PostgreSQL provider extensions for EFCore.ComplexIndexes — GIN, GiST, BRIN, SP-GiST, and Hash index support for complex type properties.

EFCore.ComplexIndexes.SqlServer

SQL Server provider extensions for EFCore.ComplexIndexes — clustered, covering (INCLUDE), online-built, and fill-factor index options for complex type properties.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.3.0 205 9/5/2026
5.2.0 158 9/5/2026
5.1.0 132 9/5/2026
5.0.3 780 8/15/2026
5.0.2 135 8/15/2026
5.0.1 165 8/10/2026
5.0.0 125 8/10/2026
4.0.0 2,703 6/14/2026
3.1.5 7,992 6/5/2026
3.1.0 150 6/4/2026
3.0.0 135 6/3/2026
2.0.5 445 5/14/2026
2.0.2 1,098 2/14/2026
1.0.2 141 2/12/2026
1.0.1 136 2/12/2026