From c03dade0718cd0d26f3b7ea945afaa106025dd64 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 2 Feb 2026 10:30:56 +0100 Subject: [PATCH 1/2] Stub for EF 11 what's new docs --- .../core/what-is-new/ef-core-11.0/whatsnew.md | 16 ++++++++++++++++ entity-framework/toc.yml | 8 ++++++++ 2 files changed, 24 insertions(+) create mode 100644 entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md 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 new file mode 100644 index 0000000000..27dcfb9717 --- /dev/null +++ b/entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md @@ -0,0 +1,16 @@ +--- +title: What's New in EF Core 11 +description: Overview of new features in EF Core 11 +author: roji +ms.date: 02/02/2026 +uid: core/what-is-new/ef-core-11.0/whatsnew +--- + +# What's New in EF Core 11 + +EF Core 11.0 (EF11) is the next release after EF Core 10.0 and is currently in development. + +> [!TIP] +> You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section below links to the source code specific to that section. + +EF11 requires the .NET 11 SDK to build and requires the .NET 11 runtime to run. EF11 will not run on earlier .NET versions, and will not run on .NET Framework. diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index c355b57198..e0d696594d 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -61,6 +61,14 @@ href: core/what-is-new/index.md - name: Release planning process href: core/what-is-new/release-planning.md + - name: EF Core 11.0 + items: + - name: "What's new?" + href: core/what-is-new/ef-core-11.0/whatsnew.md + - name: Breaking changes + href: core/what-is-new/ef-core-11.0/breaking-changes.md + - name: Provider-facing changes + href: core/what-is-new/ef-core-11.0/provider-facing-changes.md - name: EF Core 10.0 items: - name: "What's new?" From c40cf55044268b619ad2a3242e60610333d9b3e2 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 5 Feb 2026 08:49:36 +0100 Subject: [PATCH 2/2] Preview 1 docs (#5256) Document complex type support for TPC/TPT See https://github.com/dotnet/efcore/issues/28443 Document Cosmos bulk execution See https://github.com/dotnet/efcore/issues/36599 Document Cosmos session token management See https://github.com/dotnet/efcore/issues/36504 Document migration create-and-apply without recompilation See https://github.com/dotnet/efcore/issues/37342 Document Cosmos transactional batches See https://github.com/dotnet/efcore/issues/17308 Co-authored-by: JoasE <32096708+JoasE@users.noreply.github.com> --- .../core/providers/cosmos/limitations.md | 1 + .../core/providers/cosmos/saving.md | 179 ++++++++++++++++++ .../core/what-is-new/ef-core-11.0/whatsnew.md | 153 +++++++++++++++ entity-framework/toc.yml | 2 + 4 files changed, 335 insertions(+) create mode 100644 entity-framework/core/providers/cosmos/saving.md diff --git a/entity-framework/core/providers/cosmos/limitations.md b/entity-framework/core/providers/cosmos/limitations.md index 26cc0f153c..e51f59be17 100644 --- a/entity-framework/core/providers/cosmos/limitations.md +++ b/entity-framework/core/providers/cosmos/limitations.md @@ -11,6 +11,7 @@ The Azure Cosmos DB database provider targets the Azure Cosmos DB NoSQL store, w Common EF Core patterns that either do not apply, or are a pit-of-failure, when using a document database include: +- Azure Cosmos DB does not provide relational-style transactions or full ACID guarantees across any number of operations and tables. However, the EF Core Azure Cosmos DB provider does use [Transactional batches](/azure/cosmos-db/transactional-batch) when possible; see [Saving data](xref:core/providers/cosmos/saving) for further details. - Schema migration is not supported, since there is no defined schema for the documents. However, there could be other mechanisms for dealing with evolving data shapes that do make sense with Azure Cosmos DB NoSQL, For example, [Schema versioning pattern with Azure Cosmos DB](https://github.com/dotnet/efcore/issues/23753), and [Azure Cosmos DB data migration](https://github.com/dotnet/efcore/issues/11099). - Reverse-engineering (scaffolding) a model from an existing database is not supported. Again, this is not supported because there is no defined database schema to scaffold from. However, see [Use shape of documents in the Azure Cosmos DB database to scaffold a schema](https://github.com/dotnet/efcore/issues/30290). - Schema concepts defined on the EF model, like indexes and constraints, are ignored when using a document database, since there is no schema. Note that Azure Cosmos DB NoSQL performs [automatic indexing of documents](/azure/cosmos-db/index-overview). diff --git a/entity-framework/core/providers/cosmos/saving.md b/entity-framework/core/providers/cosmos/saving.md new file mode 100644 index 0000000000..b2f1da1a7c --- /dev/null +++ b/entity-framework/core/providers/cosmos/saving.md @@ -0,0 +1,179 @@ +--- +title: Saving Data - Azure Cosmos DB Provider - EF Core +description: Saving data with the Azure Cosmos DB EF Core Provider +author: roji +ms.date: 02/02/2026 +uid: core/providers/cosmos/saving +--- +# Saving Data with the EF Core Azure Cosmos DB Provider + +## Saving basics + +Saving data with the Azure Cosmos DB provider works in a similar fashion to other providers. You add, modify or remove entities, and then call to persist those changes to the database. For more information on the basics of saving, see [Saving data](xref:core/saving/index). + +## Transactionality and transactional batches + +> [!NOTE] +> Transactional batches support is being introduced in EF Core 11, which is currently in preview. + +Azure Cosmos DB provides limited support for atomic transactions; this is a common limitation of document databases, where the focus is on scalability and availability rather than strict transactional semantics. Azure Cosmos DB does support [transactional batches](/azure/cosmos-db/transactional-batch), which allow operations to be executed together as a batch within a single partition (see additional limitations below). Atomicity is guaranteed within a single batch: if any operation fails, the entire batch is rolled back and none of its changes are applied. However, once a batch is written, it cannot be rolled back or deferred, and atomicity cannot be enforced across multiple batches. Transactional batches also provide a performance benefit, as multiple documents can be updated in a single roundtrip, rather than performing a roundtrip for each update. + +Starting with EF 11, the EF Core Azure Cosmos DB provider leverages transactional batches by default whenever possible, providing a best-effort approximation of atomicity (and optimal performance) when saving changes. The batching behavior can be controlled by the property, allowing developers to trade off between performance, consistency guarantees, and failure behavior depending on the application’s needs. + +* **Auto** (default) – EF automatically groups operations into transactional batches, which are executed sequentially. If a batch fails, execution stops immediately and no subsequent changes are saved, while any previously successful batches remain committed. This generally provides good performance when performing multiple operations that can be grouped by partition key value, with a best-effort approximation of atomicity. +* **Never** – All operations are performed individually and sequentially, in the exact order they were tracked. This avoids batching and can be slower, especially for large numbers of changes. This was the behavior prior to version 11. +* **Always** – Requires that all operations can be executed as a single transaction batch; if any operation cannot be included in a batch (see [Limitations](#limitations)), an exception is thrown. This allows you to guarantee full atomicity (and a single roundtrip) when executing `SaveChangesAsync`, but it is then up to you to manually ensure that all operations can be performed in a transactional batch. + +Here is an example of using , which causes `SaveChangesAsync` to fail because too many operations are attempted: + +```csharp +using var context = new BlogsContext(); +context.Database.AutoTransactionBehavior = AutoTransactionBehavior.Always; +context.AddRange(Enumerable.Range(0, 101).Select(i => new Post())); // 101 entries exceeds the batch item limit of 100. +await context.SaveChangesAsync(); // Throws InvalidOperationException since the changes cannot be saved in a single batch. +``` + +### Limitations + +* Transactional batches can only be performed within a single partition. +* Transactional batches can contain only up to 100 operations, and cannot surpass 2MB of data in total. +* Azure Cosmos DB does not allow document writes with [pre- or post-triggers](/azure/cosmos-db/stored-procedures-triggers-udfs#triggers) to be part of a transactional batch. Because of this, any entities configured with triggers are executed separately and before any transactional batches. This can affect ordering and consistency in mixed scenarios. + +## Bulk execution + +> [!NOTE] +> Bulk execution is being introduced in EF Core 11, which is currently in preview. + +Prior to version 11, the Azure Cosmos DB provider executed document operations sequentially when calling `SaveChangesAsync`; when saving a large number of entities, this was slow as each operation waits for the previous one to complete before starting. Version 11 enables [transactional batches](#transactionality-and-transactional-batches), which allow operations to be batched together for better performance. However, transactional batches can only be used against a single partition, and have various limitations (see the documentation above). + +An alternative approach is to use Azure Cosmos DB supports _bulk execution_, which allows multiple document operations to be executed in parallel and across DbContext instances, significantly improving throughput when saving many entities at once. This is especially useful for data loading scenarios, batch operations, or any situation where you need to save many entities. + +To enable bulk execution, configure your context using the `BulkExecutionEnabled()` option: + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseCosmos( + "https://localhost:8081", + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", + databaseName: "OrdersDB", + options => options.BulkExecutionEnabled()); +``` + +With bulk execution enabled, document write operations are executed in parallel rather than sequentially. This can provide significant performance improvements when saving multiple entities, especially in scenarios involving hundreds or thousands of documents. However, make sure to understand [the caveats](https://devblogs.microsoft.com/cosmosdb/introducing-bulk-support-in-the-net-sdk/#what-are-the-caveats) before enabling this. Note that the behavior of `SaveChangesAsync` remains the same from an API perspective; it's only the internal execution that changes to take advantage of Azure Cosmos DB's bulk capabilities. + +For more information on bulk execution in Azure Cosmos DB, see the following Azure documentation: + +* [Introducing bulk support in the .NET SDK](https://devblogs.microsoft.com/cosmosdb/introducing-bulk-support-in-the-net-sdk/) +* [Bulk updates with optimistic concurrency control](https://devblogs.microsoft.com/cosmosdb/bulk-updates-with-optimistic-concurrency-control/) + +## Session token management + +> [!NOTE] +> Session token management is being introduced in EF Core 11, which is currently in preview. + +Azure Cosmos DB uses [session tokens](/azure/cosmos-db/consistency-levels#session-consistency) to track read-your-writes consistency within a session. When using session consistency (the default), each read or write operation returns a session token that can be used in subsequent requests to ensure that the requesting client reads its own writes. + +By default, the Azure Cosmos DB .NET SDK manages session tokens automatically within a single `CosmosClient` instance. However, in some scenarios you may need to manage session tokens manually: + +* When your application uses a round-robin load balancer that doesn't maintain session affinity between HTTP requests +* When session tokens need to be persisted and restored across application restarts +* When session tokens need to be shared between different `DbContext` instances or application processes + +### Configuring session token management mode + +To enable manual session token management, configure `SessionTokenManagementMode()` when setting up your context: + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseCosmos( + "", + databaseName: "OrdersDB", + options => options.SessionTokenManagementMode(SessionTokenManagementMode.SemiAutomatic)); +``` + +The following modes are available: + +Mode | Description +-------------------|------------ +`FullyAutomatic` | The default mode. Uses the underlying Cosmos DB SDK automatic session token management. `GetSessionTokens` and `UseSessionTokens` methods will throw when invoked. +`SemiAutomatic` | Allows overwriting the SDK's automatic session token management via `UseSessionTokens`. If `UseSessionTokens` has not been called for a container, the SDK's automatic management is used. EF tracks session tokens which can be retrieved via `GetSessionTokens`. +`Manual` | Fully replaces SDK automatic session token management. Only session tokens specified via `UseSessionTokens` or tracked by EF operations are used. +`EnforcedManual` | Same as `Manual`, but throws an exception if `UseSessionTokens` wasn't called for the container before executing an operation on it. + +### Retrieving session tokens + +After performing read or write operations, you can retrieve the session tokens tracked by EF: + +```csharp +// Get the session token for the default container +string? sessionToken = context.Database.GetSessionToken(); + +// Get session tokens for all containers +IReadOnlyDictionary allTokens = context.Database.GetSessionTokens(); +``` + +### Setting session tokens + +Before performing read operations, you can set session tokens to ensure you read your own writes: + +```csharp +// Set the session token for the default container +context.Database.UseSessionToken(sessionToken); + +// Set session tokens for all containers +context.Database.UseSessionTokens(sessionTokens); +``` + +### Appending session tokens + +You can also append session tokens to the existing ones. This is useful when you have session tokens from multiple sources and want to combine them: + +```csharp +// Append a session token for the default container +context.Database.AppendSessionToken(sessionToken); + +// Append session tokens for the specified containers +context.Database.AppendSessionTokens(sessionTokens); +``` + +### Example: Session token management in a load-balanced web application + +The following example demonstrates how to manage session tokens in a web application with multiple instances behind a round-robin load balancer: + +```csharp +// After writing data, retrieve and store the session token (e.g., in a cookie or header) +public async Task CreateDocument(DocumentDto dto) +{ + await using var context = new MyCosmosContext(); + + var document = new Document { Name = dto.Name }; + context.Documents.Add(document); + await context.SaveChangesAsync(); + + // Retrieve the session token to return to the client + var sessionToken = context.Database.GetSessionToken(); + + // Store in response header for the client to send back in subsequent requests + Response.Headers["x-cosmos-session-token"] = sessionToken; + + return Ok(document.Id); +} + +// Before reading data, apply the session token from the client +public async Task GetDocument(int id) +{ + await using var context = new MyCosmosContext(); + + // Get the session token from the request header + if (Request.Headers.TryGetValue("x-cosmos-session-token", out var sessionToken)) + { + context.Database.UseSessionToken(sessionToken!); + } + + var document = await context.Documents.FindAsync(id); + return document is not null ? Ok(document) : NotFound(); +} +``` + +> [!WARNING] +> Manual session token management can break session consistency when not handled properly. Only use manual mode when you have a specific need, such as running behind a load balancer without session affinity. For more information, see [Utilize session tokens](/azure/cosmos-db/nosql/how-to-manage-consistency?tabs=portal%2Cdotnetv2%2Capi-async#utilize-session-tokens) in the Azure Cosmos DB 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 27dcfb9717..d3c56b5829 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 @@ -14,3 +14,156 @@ EF Core 11.0 (EF11) is the next release after EF Core 10.0 and is currently in d > You can run and debug into the samples by [downloading the sample code from GitHub](https://github.com/dotnet/EntityFramework.Docs). Each section below links to the source code specific to that section. EF11 requires the .NET 11 SDK to build and requires the .NET 11 runtime to run. EF11 will not run on earlier .NET versions, and will not run on .NET Framework. + +## Complex types + + + +### Complex types and JSON columns on entity types with TPT/TPC inheritance + +EF Core has supported complex types and JSON columns for several versions, allowing you to model and persist nested, structured data within your entities. However, until now these features could not be used on entities with TPT (table-per-type) or TPC (table-per-concrete-type) inheritance. + +Starting with EF 11, you can now use complex types and JSON columns on entity types with TPT and TPC inheritance mappings. For example, consider the following entity types with a TPT inheritance strategy: + +```csharp +public abstract class Animal +{ + public int Id { get; set; } + public string Name { get; set; } + public required AnimalDetails Details { get; set; } +} + +public class Dog : Animal +{ + public string Breed { get; set; } +} + +public class Cat : Animal +{ + public bool IsIndoor { get; set; } +} + +[ComplexType] +public class AnimalDetails +{ + public DateTime BirthDate { get; set; } + public string? Veterinarian { get; set; } +} +``` + +With the following TPT mapping configuration: + +```csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity().UseTptMappingStrategy(); +} +``` + +EF 11 now properly supports this scenario, creating the `Details_BirthDate` and `Details_Veterinarian` columns on the `Animal` table for the complex type properties. + +Similarly, JSON columns are now supported with TPT/TPC. The following configuration maps the `Details` property to a JSON column: + +```csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + modelBuilder.Entity() + .UseTptMappingStrategy() + .ComplexProperty(a => a.Details, b => b.ToJson()); +} +``` + +This enhancement removes a significant limitation when modeling complex domain hierarchies, allowing you to combine the flexibility of TPT/TPC inheritance with the power of complex types and JSON columns. + +For more information on inheritance mapping strategies, see [Inheritance](xref:core/modeling/inheritance). + +## Cosmos DB + + + +### Transactional batches + +Azure Cosmos DB supports [transactional batches](/azure/cosmos-db/transactional-batch), which allow multiple operations to be executed atomically and in a single roundtrip against a single partition. Starting with EF Core 11, the provider leverages transactional batches by default, providing best-effort atomicity and improved performance when saving changes. + +The batching behavior can be controlled via the property: + +* **Auto** (default): Operations are grouped into transactional batches by container and partition. Batches are executed sequentially; if a batch fails, subsequent batches are not executed. +* **Never**: All operations are performed individually and sequentially (the pre-11 behavior). +* **Always**: Requires all operations to fit in a single transactional batch; throws if they cannot. + +For more information, [see the documentation](xref:core/providers/cosmos/saving#transactionality-and-transactional-batches). + +This feature was contributed by [@JoasE](https://github.com/JoasE) - many thanks! + + + +### Bulk execution + +Azure Cosmos DB supports _bulk execution_, which allows multiple document operations to be executed in parallel and across DbContext instances, significantly improving throughput when saving many entities at once. EF Core now supports enabling bulk execution: + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseCosmos( + "", + databaseName: "OrdersDB", + options => options.BulkExecutionEnabled()); +``` + +For more information, [see the documentation](xref:core/providers/cosmos/saving#bulk-execution). + +This feature was contributed by [@JoasE](https://github.com/JoasE) - many thanks! + + + +### Session token management + +Azure Cosmos DB uses session tokens to track read-your-writes consistency within a session. When running in an environment with multiple instances (e.g., with round-robin load balancing), you may need to manually manage session tokens to ensure consistency across requests. + +EF Core now provides APIs to retrieve and set session tokens on a `DbContext`. To enable manual session token management, configure the `SessionTokenManagementMode()`: + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseCosmos( + "", + databaseName: "OrdersDB", + options => options.SessionTokenManagementMode(SessionTokenManagementMode.SemiAutomatic)); +``` + +You can then retrieve and use session tokens: + +```csharp +// After performing operations, retrieve the session token +var sessionToken = context.Database.GetSessionToken(); + +// Later, in a different context instance, apply the session token before reading +context.Database.UseSessionToken(sessionToken); +var result = await context.Documents.FindAsync(id); +``` + +For more information, [see the documentation](xref:core/providers/cosmos/saving#session-token-management). + +This feature was contributed by [@JoasE](https://github.com/JoasE) - many thanks! + +## Migrations + + + +### Create and apply migrations in one step + +The `dotnet ef database update` command now supports creating and applying a migration in a single step using the new `--add` option. This uses Roslyn to compile the migration at runtime, enabling scenarios like .NET Aspire and containerized applications where recompilation isn't possible: + +```dotnetcli +dotnet ef database update InitialCreate --add +``` + +This command scaffolds a new migration named `InitialCreate`, compiles it using Roslyn, and immediately applies it to the database. The migration files are still saved to disk for source control and future recompilation. The same options available for `dotnet ef migrations add` can be used: + +```dotnetcli +dotnet ef database update AddProducts --add --output-dir Migrations/Products --namespace MyApp.Migrations +``` + +In PowerShell, use the `-Add` parameter: + +```powershell +Update-Database -Migration InitialCreate -Add +``` diff --git a/entity-framework/toc.yml b/entity-framework/toc.yml index e0d696594d..560304cc47 100644 --- a/entity-framework/toc.yml +++ b/entity-framework/toc.yml @@ -450,6 +450,8 @@ href: core/providers/cosmos/modeling.md - name: Querying href: core/providers/cosmos/querying.md + - name: Saving data + href: core/providers/cosmos/saving.md - name: Work with unstructured data href: core/providers/cosmos/unstructured-data.md - name: Vector search