Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion entity-framework/core/managing-schemas/migrations/applying.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Applying Migrations - EF Core
description: Strategies for applying schema migrations to production and development databases using Entity Framework Core
author: SamMonoRT
ms.date: 10/29/2024
ms.date: 04/16/2026
uid: core/managing-schemas/migrations/applying
ms.custom: sfi-ropc-nochange
---
Expand Down Expand Up @@ -341,3 +341,24 @@ Note that `MigrateAsync()` builds on top of the `IMigrator` service, which can b
>
> * Carefully consider before using this approach in production. Experience has shown that the simplicity of this deployment strategy is outweighed by the issues it creates. Consider generating SQL scripts from migrations instead.
> * Don't call `EnsureCreatedAsync()` before `MigrateAsync()`. `EnsureCreatedAsync()` bypasses Migrations to create the schema, which causes `MigrateAsync()` to fail.

## Migration locking
Comment thread
AndriySvyryd marked this conversation as resolved.

Starting with EF Core 9, <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.MigrateAsync*> and <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate*> automatically acquire a database-wide lock before applying any migrations. This protects against database corruption that could result from multiple application instances running migrations concurrently, which is a common scenario when [applying migrations at runtime](#apply-migrations-at-runtime). The lock is held for the duration of the migration execution, including any [seeding code](xref:core/modeling/data-seeding#use-seeding-method), and is automatically released when the operation completes.

Migration locking applies when migrations are applied using any of the following methods:

* `dotnet ef database update` (.NET CLI)
* `Update-Database` (Package Manager Console)
* [Migration bundles](#bundles)
* <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.MigrateAsync*> and <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate*> (runtime migration)

[SQL scripts](#sql-scripts) are not affected by migration locking, since they are applied outside of EF Core.

> [!WARNING]
> The locking mechanism varies significantly across database providers and can involve provider-specific issues. For example, the SQLite provider uses a lock table that can become [abandoned if the process terminates unexpectedly](xref:core/providers/sqlite/limitations#concurrent-migrations-protection). Always consult your provider's documentation for details.

### Limitations

* Wrapping <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.MigrateAsync*> in an explicit transaction is not supported. See [Exception is thrown when applying migrations in an explicit transaction](xref:core/what-is-new/ef-core-9.0/breaking-changes#migrations-transaction) for details.
* On SQLite, abandoned migration locks can [block subsequent migrations](xref:core/providers/sqlite/limitations#concurrent-migrations-protection).
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/data-seeding.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ There are several ways this can be accomplished in EF Core:

## Configuration options `UseSeeding` and `UseAsyncSeeding` methods

EF 9 introduced <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseSeeding*> and <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseAsyncSeeding*> methods, which provide a convenient way of seeding the database with initial data. These methods aim to improve the experience of using custom initialization logic (explained below). They provide one clear location where all the data seeding code can be placed. Moreover, the code inside <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseSeeding*> and <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseAsyncSeeding*> methods is protected by the [migration locking mechanism](/ef/core/what-is-new/ef-core-9.0/whatsnew#concurrent-migrations) to prevent concurrency issues.
EF 9 introduced <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseSeeding*> and <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseAsyncSeeding*> methods, which provide a convenient way of seeding the database with initial data. These methods aim to improve the experience of using custom initialization logic (explained below). They provide one clear location where all the data seeding code can be placed. Moreover, the code inside <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseSeeding*> and <xref:Microsoft.EntityFrameworkCore.DbContextOptionsBuilder.UseAsyncSeeding*> methods is protected by the [migration locking mechanism](xref:core/managing-schemas/migrations/applying#migration-locking) to prevent concurrency issues.

The new seeding methods are called as part of <xref:Microsoft.EntityFrameworkCore.Storage.IDatabaseCreator.EnsureCreated*> operation, <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate*> and `dotnet ef database update` command, even if there are no model changes and no migrations were applied.

Expand Down
22 changes: 19 additions & 3 deletions entity-framework/core/providers/sqlite/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: SQLite Database Provider - Limitations - EF Core
description: Limitations of the Entity Framework Core SQLite database provider as compared to other providers
author: SamMonoRT
ms.date: 11/15/2021
ms.date: 04/16/2026
uid: core/providers/sqlite/limitations
---
# SQLite EF Core Database Provider Limitations
Expand Down Expand Up @@ -92,9 +92,25 @@ dotnet ef database update --connection "Data Source=My.db"

## Concurrent migrations protection

EF9 introduced a locking mechanism when executing migrations. It aims to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This is one of the potential problems resulting from applying migrations at runtime using the <xref:Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate%2A> method (see [Applying migrations](xref:core/managing-schemas/migrations/applying) for more information). To mitigate this, EF creates an exclusive lock on the database before any migration operations are applied.
EF9 introduced a [migration locking mechanism](xref:core/managing-schemas/migrations/applying#migration-locking) to protect against concurrent migration executions. Unlike SQL Server, which uses a session-level application lock (`sp_getapplock`) that is automatically released when the connection closes, SQLite doesn't have built-in application locks. EF Core instead creates a `__EFMigrationsLock` table and inserts a row to acquire the lock.

Unfortunately, SQLite does not have built-in locking mechanism, so EF Core creates a separate table (`__EFMigrationsLock`) and uses it for locking. The lock is released when the migration completes and the seeding code finishes execution. However, if for some reason migration fails in a non-recoverable way, the lock may not be released correctly. If this happens, consecutive migrations will be blocked from executing SQL and therefore never complete. You can manually unblock them by deleting the `__EFMigrationsLock` table in the database.
### Handling abandoned locks

If the application terminates unexpectedly (for example, the process is killed during migration), the lock row in the `__EFMigrationsLock` table may not be cleaned up. This prevents any subsequent migration from completing, because each attempt will wait indefinitely for the lock to be released.

To resolve an abandoned lock, drop the `__EFMigrationsLock` table from the database:

```sql
DROP TABLE "__EFMigrationsLock";
```

Or, alternatively, delete all rows from the table:

```sql
DELETE FROM "__EFMigrationsLock";
```

After clearing the lock, subsequent migration operations proceed normally. The table is automatically recreated as needed.

## See also

Expand Down
2 changes: 2 additions & 0 deletions entity-framework/core/what-is-new/ef-core-9.0/whatsnew.md
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,8 @@ The above were only some of the more important query improvements in EF9; see [t

EF9 introduces a locking mechanism to protect against multiple migration executions happening simultaneously, as that could leave the database in a corrupted state. This doesn't happen when migrations are deployed to the production environment using [recommended methods](/ef/core/managing-schemas/migrations/applying#sql-scripts), but can happen if migrations are applied at runtime using the [`DbContext.Database.MigrateAsync()`](/dotnet/api/microsoft.entityframeworkcore.relationaldatabasefacadeextensions.migrate) method. We recommend applying migrations at deployment, rather than as part of application startup, but that can result in more complicated application architectures (e.g. [when using .NET Aspire projects](/dotnet/aspire/database/ef-core-migrations)).

For more information, see [Migration locking](/ef/core/managing-schemas/migrations/applying#migration-locking).

> [!NOTE]
> If you are using Sqlite database, see [potential issues associated with this feature](/ef/core/providers/sqlite/limitations#concurrent-migrations-protection).

Expand Down
Loading