diff --git a/entity-framework/core/modeling/indexes.md b/entity-framework/core/modeling/indexes.md index 003ca0c9cb..cd9a891175 100644 --- a/entity-framework/core/modeling/indexes.md +++ b/entity-framework/core/modeling/indexes.md @@ -2,7 +2,7 @@ title: Indexes - EF Core description: Configuring indexes in an Entity Framework Core model author: roji -ms.date: 10/1/2021 +ms.date: 06/09/2026 uid: core/modeling/indexes --- # Indexes @@ -40,6 +40,58 @@ An index can also span more than one column: Indexes over multiple columns, also known as *composite indexes*, speed up queries which filter on index's columns, but also queries which only filter on the *first* columns covered by the index. See the [performance docs](xref:core/performance/efficient-querying#use-indexes-properly) for more information. +## Indexes on complex type properties + +Starting with EF Core 11.0, indexes can use scalar properties nested inside [complex types](xref:core/what-is-new/ef-core-10.0/whatsnew#complex-types): + +```csharp +modelBuilder.Entity() + .HasIndex(c => c.Address.PostalCode); +``` + +Composite indexes can mix regular entity properties and complex type properties: + +```csharp +modelBuilder.Entity() + .HasIndex(c => new { c.Region, c.Address.PostalCode }); +``` + +The same paths can be specified by name: + +```csharp +modelBuilder.Entity() + .HasIndex("Address.PostalCode"); +``` + +For complex types mapped to JSON columns, providers may also support indexing paths inside the JSON document: + +```csharp +modelBuilder.Entity() + .ComplexProperty(c => c.Address, b => b.ToJson()); + +modelBuilder.Entity() + .HasIndex("Address.PostalCode"); +``` + +Indexes over complex collections use collection path syntax. `[]` represents all elements, while `[0]`, `[1]`, and so on represent a specific element: + +```csharp +modelBuilder.Entity() + .ComplexCollection(o => o.Items, b => b.ToJson()); + +modelBuilder.Entity() + .HasIndex("Items[].Sku"); +``` + +The same index can be configured with a lambda expression using `Select`: + +```csharp +modelBuilder.Entity() + .HasIndex(o => o.Items.Select(i => i.Sku)); +``` + +Support for JSON-path indexes depends on the database provider. For example, the SQL Server provider creates SQL Server JSON indexes where supported, while the Azure Cosmos DB provider emits the configured paths into the container indexing policy. + ## Index uniqueness By default, indexes aren't unique: multiple rows are allowed to have the same value(s) for the index's column set. You can make an index unique as follows: @@ -148,6 +200,14 @@ In the following example, the `Url` column is part of the index key, so any quer [!code-csharp[Main](../../../samples/core/Modeling/IndexesAndConstraints/FluentAPI/IndexInclude.cs?name=IndexInclude&highlight=5-9)] +Starting with EF Core 11.0, SQL Server included columns can also refer to scalar properties nested inside complex types: + +```csharp +modelBuilder.Entity() + .HasIndex(c => c.Name) + .IncludeProperties(c => c.Address.City); +``` + ## Check constraints Check constraints are a standard relational feature that allows you to define a condition that must hold for all rows in a table; any attempt to insert or modify data that violates the constraint will fail. Check constraints are similar to non-null constraints (which prohibit nulls in a column) or to unique constraints (which prohibit duplicates), but allow arbitrary SQL expression to be defined. diff --git a/entity-framework/core/modeling/keys.md b/entity-framework/core/modeling/keys.md index bbb8ef5bec..72faa6419d 100644 --- a/entity-framework/core/modeling/keys.md +++ b/entity-framework/core/modeling/keys.md @@ -2,7 +2,7 @@ title: Keys - EF Core description: How to configure keys for entity types when using Entity Framework Core author: AndriySvyryd -ms.date: 10/14/2022 +ms.date: 06/09/2026 uid: core/modeling/keys --- # Keys @@ -53,6 +53,24 @@ public class Car *** +## Keys on complex type properties + +Starting with EF Core 11.0, keys can use scalar properties nested inside non-collection [complex types](xref:core/what-is-new/ef-core-10.0/whatsnew#complex-types). + +```csharp +modelBuilder.Entity() + .HasKey(c => c.CustomerId.Value); +``` + +The same path can be specified by name: + +```csharp +modelBuilder.Entity() + .HasKey("CustomerId.Value"); +``` + +Complex properties on the path to a key property are required. Keys can't traverse complex collections or nullable complex properties. + ## Value generation For non-composite numeric and GUID primary keys, EF Core sets up value generation for you by convention. For example, a numeric primary key in SQL Server is automatically set up to be an IDENTITY column. For more information, see [the documentation on value generation](xref:core/modeling/generated-properties) and [guidance for specific inheritance mapping strategies](xref:core/modeling/inheritance#key-generation). diff --git a/entity-framework/core/providers/cosmos/modeling.md b/entity-framework/core/providers/cosmos/modeling.md index c3c5262536..2ea7c9e633 100644 --- a/entity-framework/core/providers/cosmos/modeling.md +++ b/entity-framework/core/providers/cosmos/modeling.md @@ -2,7 +2,7 @@ title: Modeling - Azure Cosmos DB Provider - EF Core description: Configuring the model with the Azure Cosmos DB EF Core Provider author: roji -ms.date: 09/26/2024 +ms.date: 06/09/2026 uid: core/providers/cosmos/modeling --- # Configuring the model with the EF Core Azure Cosmos DB Provider @@ -67,6 +67,47 @@ If you don't configure a partition key with EF, a warning will be logged at star Once your partition key properties are properly configured, you can provide values for them in queries; see [Querying with partition keys](xref:core/providers/cosmos/querying#partition-keys) for more information. +## Indexing policy + +Starting with EF Core 11.0, the Azure Cosmos DB provider emits more of the EF model's index configuration into the container [indexing policy](/azure/cosmos-db/index-policy). + +By default, Azure Cosmos DB automatically indexes all properties. You can configure this automatic indexing policy and exclude individual paths: + +```csharp +modelBuilder.Entity() + .HasAutomaticIndexing() + .Except("/InternalNotes/?"); +``` + +To index only explicitly configured paths, configure indexes with `HasIndex`. Automatic indexing is disabled automatically as soon as any single-property index is defined, so there is no need to call `HasAutomaticIndexing(false)` explicitly: + +```csharp +modelBuilder.Entity(b => +{ + b.HasIndex(o => o.OrderNumber); + b.HasIndex(o => new { o.CustomerId, o.OrderDate }); +}); +``` + +When automatic indexing is enabled, single-property indexes are already covered by the default `/*` included path and aren't emitted separately. Composite, vector, and full-text indexes are always emitted. + +Indexes can also traverse complex type properties and complex collections. In a string path, `[]` represents all elements of a collection: + +```csharp +modelBuilder.Entity(b => +{ + b.ComplexCollection(o => o.Items); + b.HasIndex("Items[].Sku"); +}); +``` + +The same index can be configured with a lambda expression: + +```csharp +modelBuilder.Entity() + .HasIndex(o => o.Items.Select(i => i.Sku)); +``` + ## Discriminators Since multiple entity types may be mapped to the same container, EF Core always adds a `$type` discriminator property to all JSON documents you save (this property was called `Discriminator` before EF 9.0); this allows EF to recognize documents being loaded from the database, and materialize the right .NET type. Developers coming from relational databases may be familiar with discriminators in the context of [table-per-hierarchy inheritance (TPH)](xref:core/modeling/inheritance#table-per-hierarchy-and-discriminator-configuration); in Azure Cosmos DB, discriminators are used not just in inheritance mapping scenarios, but also because the same container can contain completely different document types. diff --git a/entity-framework/core/providers/sql-server/index.md b/entity-framework/core/providers/sql-server/index.md index 56d3210ba0..5512f5f984 100644 --- a/entity-framework/core/providers/sql-server/index.md +++ b/entity-framework/core/providers/sql-server/index.md @@ -2,7 +2,7 @@ title: Microsoft SQL Server Database Provider - EF Core description: Documentation for the database provider that allows Entity Framework Core to be used with Microsoft SQL Server author: AndriySvyryd -ms.date: 11/15/2021 +ms.date: 06/09/2026 uid: core/providers/sql-server/index --- # Microsoft SQL Server EF Core Database Provider @@ -113,6 +113,36 @@ To configure EF with a compatibility level, use `UseCompatibilityLevel()` as fol optionsBuilder.UseSqlServer("", o => o.UseCompatibilityLevel(170)); ``` +## JSON indexes + +Starting with EF Core 11.0, the SQL Server provider can create and scaffold [SQL Server JSON indexes](/sql/t-sql/statements/create-json-index-transact-sql) for paths inside complex types mapped to JSON columns. + +For example, the following maps a complex type to a JSON column and creates a JSON index over a nested property: + +```csharp +modelBuilder.Entity() + .ComplexProperty(c => c.Contact, b => b.ToJson().HasColumnType("json")); + +modelBuilder.Entity() + .HasIndex("Contact.Address.City"); +``` + +When SQL Server JSON indexes are supported, migrations generate SQL similar to: + +```sql +CREATE JSON INDEX [IX_Customers_Contact_Address_City] +ON [Customers]([Contact]) FOR (N'$.Address.City'); +``` + +Multiple paths inside the same JSON column can be indexed together: + +```csharp +modelBuilder.Entity() + .HasIndex(["Contact.Address.City", "Contact.PhoneNumber"]); +``` + +Paths through JSON arrays can use numeric indexers, for example `Orders[0].Number`. SQL Server JSON indexes don't support wildcard indexes over every array element. + ## Connection resiliency EF includes functionality for automatically retrying failed database commands; for more information, [see the documentation](xref:core/miscellaneous/connection-resiliency). When using and , connection resiliency is automatically set up with the appropriate settings specific for those databases. Otherwise, when using , configure the provider with as shown in the connection resiliency documentation. diff --git a/entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md b/entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md index 9e8327235d..e6b7735c57 100644 --- a/entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md +++ b/entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md @@ -2,7 +2,7 @@ title: What's New in EF Core 11 description: Overview of new features in EF Core 11 author: roji -ms.date: 04/22/2026 +ms.date: 06/09/2026 uid: core/what-is-new/ef-core-11.0/whatsnew --- @@ -106,6 +106,39 @@ modelBuilder.Entity() This simplifies model configuration by removing the need to explicitly navigate through intermediate complex type builders to reach the property you want to configure. + + +### Keys and indexes on complex type properties + +Keys and indexes can now use scalar properties nested inside non-collection complex types: + +```csharp +modelBuilder.Entity() + .HasKey(c => c.CustomerId.Value); + +modelBuilder.Entity() + .HasIndex(c => c.Address.PostalCode); +``` + +The same paths can be configured by name: + +```csharp +modelBuilder.Entity() + .HasIndex("Address.PostalCode"); +``` + +For relational providers, indexes can also target paths inside complex types mapped to JSON columns. Complex collection paths use `[]` for all elements or a numeric indexer for a specific element: + +```csharp +modelBuilder.Entity() + .ComplexCollection(o => o.Items, b => b.ToJson()); + +modelBuilder.Entity() + .HasIndex("Items[].Sku"); +``` + +For more information, see [Keys](xref:core/modeling/keys#keys-on-complex-type-properties) and [Indexes](xref:core/modeling/indexes#indexes-on-complex-type-properties). + ### Stabilization and bug fixes @@ -508,6 +541,29 @@ WHERE JSON_CONTAINS([b].[JsonData], 8, N'$.Rating') = 1 For the full `JSON_CONTAINS` SQL Server documentation, see [`JSON_CONTAINS`](/sql/t-sql/functions/json-contains-transact-sql). + + +### JSON indexes + +EF Core 11 can create and scaffold [SQL Server JSON indexes](/sql/t-sql/statements/create-json-index-transact-sql) for paths inside complex types mapped to JSON columns: + +```csharp +modelBuilder.Entity() + .ComplexProperty(c => c.Contact, b => b.ToJson().HasColumnType("json")); + +modelBuilder.Entity() + .HasIndex("Contact.Address.City"); +``` + +This generates SQL similar to: + +```sql +CREATE JSON INDEX [IX_Customers_Contact_Address_City] +ON [Customers]([Contact]) FOR (N'$.Address.City'); +``` + +For more information, see [JSON indexes](xref:core/providers/sql-server/index#json-indexes). + ### Temporal period properties mapped to CLR properties @@ -602,6 +658,31 @@ Complex types are generally a better fit than owned types when mapping to JSON d This feature was contributed by [@JoasE](https://github.com/JoasE) - many thanks! + + +### Indexes and indexing policy + +EF Core 11 adds support for more Azure Cosmos DB indexing policy configuration. You can now disable automatic indexing, exclude individual paths when automatic indexing is enabled, and emit explicit single-property, composite, vector, and full-text indexes: + +```csharp +modelBuilder.Entity(b => +{ + b.HasAutomaticIndexing() + .Except("/InternalNotes/?"); + + b.HasIndex(o => new { o.CustomerId, o.OrderDate }); +}); +``` + +Indexes can also traverse complex type properties and complex collections: + +```csharp +modelBuilder.Entity() + .HasIndex(o => o.Items.Select(i => i.Sku)); +``` + +For more information, see [Indexing policy](xref:core/providers/cosmos/modeling#indexing-policy). + ### Transactional batches