Entity Framework Core: Migrations Explained

Today, I want to share a bit of my journey while working on a real-world project where I had to manage database changes properly using Entity Framework Core. I know, “migrations” might sound a bit intimidating at first, especially if you’re new to EF Core or you haven’t handled schema evolution yet. Believe me, I was also there once, scratching my head. So let’s go through this together, like how I learned it (sometimes the hard way).

First Things First: What is EF Core Migration?

Imagine you already have your application running, and suddenly the client asks you to add a new feature, like “store the user’s birthday.” That means your database needs a new column.

Migrations help you update your database schema without needing to manually alter tables every time you make a change in your model classes. It’s a version control for your database structure.

Simply put: Migrations = Model changes -> SQL Changes -> Database updated automatically.

Why Migrations Matter?

In my project, we started simple. Just a few tables. At first, I thought, “I will just manually edit my tables in SQL Server, no big deal.” But when the project grew, I realized I was creating a monster. Production data, test data, different environments… it was getting messy. Sometimes an ALTER TABLE command missed, sometimes the developer’s local database was different from the staging server. Disaster waiting to happen!

Once I started using EF Core Migrations properly, everything became smoother. And safer. My team members could update their databases consistently without worries.


Setting Up Migrations in EF Core

Alright, let’s get our hands a bit dirty.

Step 1: Install Required Packages

If you haven’t installed these yet, make sure your project has:

Bash
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer (or your database provider)

You can install via NuGet Package Manager or simply:

Bash
dotnet add package Microsoft.EntityFrameworkCore.Design
Step 2: Create Your DbContext and Models

Example:

C#
public class AppDbContext : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Your_Connection_String_Here");
    }
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

In this example, AppDbContext is the bridge between your application and your database. It inherits from DbContext, which is a base class provided by EF Core that gives you all the functionality needed to interact with the database. Inside it, we declare a DbSet named Users, which represents a table where each User object is a row in the database. The OnConfiguring method tells EF Core how to connect to your database, in this case, it uses SQL Server, and you specify your connection string here. Later on, for better practice and cleaner code, you can move your connection strings to a configuration file like appsettings.json instead of hardcoding them.

Step 3: Add Your First Migration

Run this command:

Bash
dotnet ef migrations add InitialCreate

This will create a Migrations folder with a snapshot of your database schema.

Step 4: Apply the Migration

Run:

Bash
dotnet ef database update

Boom! Your database is created based on your models.


A Small Real-World Scenario

In our project, one day we needed to add a DateOfBirth field for Users.

We just:

1. Update the model.
C#
public DateTime? DateOfBirth { get; set; }
2. Added a new migration.
Bash
dotnet ef migrations add AddDateOfBirthToUser
3. Update the database.
Bash
dotnet ef database update

That’s it. No manual ALTER TABLE. No forgetting a field. Everyone on the team ran the same migrations.


Common Migration Commands You Should Know

Here are a few I personally used a lot:

Add Migration

Bash
dotnet ef migrations add MigrationName

Remove Last Migration

Bash
dotnet ef migrations remove

Update Database

Bash
dotnet ef database update

Script Migration (for manual deployment)

Bash
dotnet ef migrations script

Tips and Things I Learned the Hard Way

1. Never Edit Migration Files Manually (if not expert)

They are auto-generated for a reason. If you must tweak something, better rollback and re-create the migration cleanly.

2. Keep Migration Names Clear

Use meaningful names like AddDateOfBirthToUser instead of Update1, NewMigration2, etc. Future you will thank you.

3. Be Careful on Production Databases

On live systems, running migrations blindly can cause downtime. Always test migrations first on a clone database.

4. Migration History is Stored

EF Core tracks applied migrations inside a special table called __EFMigrationsHistory.


Applying Migrations Automatically (Careful!)

Sometimes, especially in small apps or internal tools, you might want your app to apply migrations automatically at startup.

Add this in your Program.cs:

C#
using (var scope = app.Services.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
    db.Database.Migrate();
}

This will apply any pending migrations automatically when the app starts. Use it wisely.


Useful Resources

If you want to deep dive more, here are official and excellent references I personally studied too:

Please check them out if you want to become really good in EF Core!

Assi Arai
Assi Arai
Articles: 31