In this lesson, you will learn how to orchestrate the evolution of your database schema by mastering the generation, application, and rollback of incremental changes using EF Core Migrations.
The Migration Lifecycle
Think of a migration as a version-controlled "diff" for your database. Instead of manually editing tables, you tell EF Core how your C# model has changed, and it generates an incremental script to align the database.
The lifecycle consists of three distinct phases:
- Generation: When you modify your entity classes or Fluent API configurations, you run
dotnet ef migrations add <Name>. EF Core compares your current model against theModelSnapshot(the state of the last migration) and generates two files: aDesignerfile (the snapshot) and aMigrationclass containingUp()andDown()methods. - Application: Running
dotnet ef database updateexecutes the pendingUp()methods in sequence. This transforms your schema to match your current domain model. - Rollback: If a deployment goes wrong, you can revert to a previous state by running
dotnet ef database update <PreviousMigrationName>. EF Core identifies all migrations between your current state and the target, executing theirDown()methods in reverse order to restore the schema.
Example: Tracking Changes
If you add a PhoneNumber property to your User entity, the lifecycle looks like this:
// Generated code in your Migration file
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "PhoneNumber",
table: "Users",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PhoneNumber",
table: "Users");
}
The Up method applies the new column, while the Down method provides a safety net, allowing you to undo the operation perfectly if required. Always inspect these generated files before applying them, as complex refactors (like renaming columns) may require manual intervention inside the Up and Down methods to prevent data loss.
Key Takeaway: Migrations treat your database schema as code, providing a repeatable, reversible path for schema evolution through explicit Up and Down operations.