Database Migrations in C# (.NET): Complete Guide
Managing database schema changes is a critical task when developing any application in C# (.NET). Migrations allow you to version, track, and automatically apply database structure changes (adding tables, columns, indexes) in sync with your application code. In the .NET ecosystem, there are several mature tools for this task. In this article, we will thoroughly examine three main approaches: the built-in Entity Framework Core mechanism, and the specialized libraries FluentMigrator and DbUp.
1. Entity Framework Core Migrations (EF Core)
The most popular approach for projects already using the Entity Framework Core ORM. Migrations are tightly integrated with your data model (Code-First approach).
Installation and Setup
To work with migrations, you need to install the package:
dotnet add package Microsoft.EntityFrameworkCore.ToolsCreating and Applying a Migration
After modifying your C# models (e.g., adding a new Email property to the User class), run the following in the terminal:
dotnet ef migrations add AddEmailToUserdotnet ef database updateThe first command creates a migration file with auto-generated C# code. The second applies it to your database.
Example Migration Code (generated file):
public partial class AddEmailToUser : Migration{ protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn<string>( name: "Email", table: "Users", type: "nvarchar(200)", nullable: true); }
protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropColumn( name: "Email", table: "Users"); }}The Up method applies changes, Down rolls them back.
Advantages and Disadvantages of EF Core Migrations
- Pros: Tight integration with models, automatic code generation, rollback support, built into the .NET ecosystem.
- Cons: Tied to EF Core, complexity with non-trivial changes (e.g., renaming columns), potential team conflicts.
2. FluentMigrator
This is an independent, lightweight migration library not tied to any specific ORM. Migrations are written manually in C# using a fluent interface.
Installation
dotnet add package FluentMigratorExample Migration
[Migration(202310010001)]public class CreateUserTable : Migration{ public override void Up() { Create.Table("Users") .WithColumn("Id").AsInt32().PrimaryKey().Identity() .WithColumn("Name").AsString(100).NotNullable() .WithColumn("Email").AsString(200).Nullable(); Create.Index("IX_Users_Email") .OnTable("Users") .OnColumn("Email"); }
public override void Down() { Delete.Table("Users"); }}Running Migrations
A runner is used to execute migrations. Example configuration in Program.cs:
var serviceProvider = new ServiceCollection() .AddFluentMigratorCore() .ConfigureRunner(rb => rb .AddSqlServer() .WithGlobalConnectionString("YourConnectionString") .ScanIn(typeof(CreateUserTable).Assembly).For.Migrations()) .BuildServiceProvider();
using var scope = serviceProvider.CreateScope();var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();runner.MigrateUp();