Code-First Migrations
🎯 What You'll Learn
- What are migrations
- Creating migrations
- Applying migrations
- Updating the database
- Rolling back migrations
- Migration best practices
What are Migrations?
Migrations are a way to incrementally update your database schema to match your entity model while preserving existing data.
Why Use Migrations?
- Version control: Track database schema changes
- Team collaboration: Share schema changes via source control
- Deployment: Apply changes to production databases
- Rollback: Revert to previous schema versions
- Data preservation: Update schema without losing data
Installing EF Core Tools
# Install EF Core Tools globally
dotnet tool install --global dotnet-ef
# Or update if already installed
dotnet tool update --global dotnet-ef
# Add Design package to project
dotnet add package Microsoft.EntityFrameworkCore.Design
Creating Your First Migration
dotnet ef migrations add InitialCreate
This creates a migration file in the Migrations folder:
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Products",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(maxLength: 100, nullable: false),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
Quantity = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Products");
}
}
Up(): Applies the migration (creates tables, columns, etc.)
Down(): Reverts the migration (drops tables, columns, etc.)
Applying Migrations
Update Database
dotnet ef database update
This executes all pending migrations and creates/updates the database.
Apply at Runtime
var app = builder.Build();
// Apply migrations on startup
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<InvenTrackDbContext>();
context.Database.Migrate();
}
app.Run();
Be careful applying migrations automatically in production. Consider using deployment scripts or manual application for better control.
Adding More Migrations
Modify Entity
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public string? Description { get; set; } // NEW
public int Quantity { get; set; }
}
Create Migration
dotnet ef migrations add AddProductDescription
public partial class AddProductDescription : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Description",
table: "Products",
maxLength: 500,
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Description",
table: "Products");
}
}
Apply Migration
dotnet ef database update
Common Migration Commands
| Command | Description |
|---|---|
dotnet ef migrations add [Name] |
Create a new migration |
dotnet ef database update |
Apply all pending migrations |
dotnet ef migrations list |
List all migrations |
dotnet ef migrations remove |
Remove last migration (if not applied) |
dotnet ef database update [Migration] |
Update to specific migration |
dotnet ef database update 0 |
Revert all migrations |
dotnet ef migrations script |
Generate SQL script |
Rolling Back Migrations
Revert to Previous Migration
# Revert to specific migration
dotnet ef database update InitialCreate
# Revert all migrations
dotnet ef database update 0
Remove Last Migration
dotnet ef migrations remove
Generating SQL Scripts
# Generate script for all migrations
dotnet ef migrations script
# Generate script from specific migration
dotnet ef migrations script InitialCreate AddProductDescription
# Generate idempotent script (safe to run multiple times)
dotnet ef migrations script --idempotent
# Output to file
dotnet ef migrations script -o migration.sql
Seeding Data
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>().HasData(
new Category { Id = 1, Name = "Electronics" },
new Category { Id = 2, Name = "Furniture" },
new Category { Id = 3, Name = "Office Supplies" }
);
modelBuilder.Entity<Product>().HasData(
new Product
{
Id = 1,
Name = "Laptop",
Price = 999.99m,
Quantity = 10,
CategoryId = 1
},
new Product
{
Id = 2,
Name = "Mouse",
Price = 29.99m,
Quantity = 50,
CategoryId = 1
}
);
}
After adding seed data, create a migration:
dotnet ef migrations add SeedData
dotnet ef database update
Complete InvenTrack Example
# 1. Install tools
dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.Design
# 2. Create initial migration
dotnet ef migrations add InitialCreate
# 3. Apply to database
dotnet ef database update
# 4. Make changes to entities...
# 5. Create new migration
dotnet ef migrations add AddProductDescription
# 6. Apply changes
dotnet ef database update
# 7. View migration history
dotnet ef migrations list
Best Practices
- Descriptive names: Use clear migration names (AddProductDescription)
- Small migrations: Create focused, single-purpose migrations
- Review generated code: Always check migration files
- Source control: Commit migrations to version control
- Test migrations: Test on development database first
- Idempotent scripts: Use for production deployments
- Backup first: Always backup production before migrating
- Custom SQL: Add custom SQL in migrations when needed
Key Takeaways
- Migrations: Version control for database schema
- dotnet ef: Command-line tool for migrations
- Up/Down: Apply and revert migrations
- Add migration: Create new migration from model changes
- Update database: Apply pending migrations
- Rollback: Revert to previous migration
- SQL scripts: Generate for manual deployment
- Seed data: Use HasData() for initial data
You now understand Code-First Migrations! In the next section, we'll explore Querying Data with LINQ—how to retrieve and filter data from your database using C# LINQ syntax.