In this article, we will show how to revert a migration in EF Core. Entity Framework Core is an excellent tool for managing data structure by using familiar object types. If you need a refresher on the basics of EF Core, be sure to check out our full Entity Framework Core series!

Now EF Core is great at helping us create “Code First” data models, but when it comes to updating those models, migrations can be less than straightforward.

One of the least intuitive things we can do in EF Core is to roll back the changes in a migration after we’ve already updated the database.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
To download the source code for this article, you can visit our GitHub repository.

Create a New Project with EF Core

Let’s set ourselves up by creating a new .NET project using the dotnet CLI:

dotnet new console --name RevertMigration

We will add the Entity Framework Core package from NuGet. EF Core supports several database types, but for simplicity, we’ll use SQLite:

dotnet add package Microsoft.EntityFrameworkCore.Sqlite

Add DB Context and Entity Models>

Now that we have EF Core installed, let’s create some entity models and add them to a data context. First, we’ll create an Airplane object:

public class Airplane
{
    public int Id { get; set; }
    public string? TailNumber { get; set; }
    public int? NumberOfEngines { get; set; }
    public double? MaxAirSpeed { get; set; }
    public bool? RunsOnJetFuel { get; set; }

    public int? HangarId { get; set; }
    public Hangar? Hangar { get; set; }
}

Next, let’s create a Hangar to park our planes:

public class Hangar
{
    public int Id { get; set; }
    public string? HangarNumber { get; set; }
    public bool HasDoors { get; set; }

    public List Airplanes { get; } = new();
}

And finally, let’s create our DBContext:

public class AirportDbContext : DbContext
{
    public DbSet Airplanes { get; set; }
    public DbSet Hangars { get; set; }

    public string DbPath { get; }

    public AirportDbContext()
    {
        var folder = Environment.SpecialFolder.LocalApplicationData;
        var path = Environment.GetFolderPath(folder);
        DbPath = Path.Join(path, "airport.db");
    }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite($"Data Source={DbPath}");
}

We’ll run the following commands to install EF Core Tools and scaffold our data context:

dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet ef migrations add Init
dotnet ef database update

Great, now we have a database! Let’s add a new hangar and an airplane, saving them to our database as we go:

using var db = new AirportDbContext();

Console.WriteLine("Inserting a new hangar");
db.Add(new Hangar
{
    HangarNumber = "HANGAR_01",
    HasDoors = true
});
db.SaveChanges();

var hangar = db.Hangars
    .OrderBy(h => h.Id)
    .Last();
Console.WriteLine($"Just created hangar: {hangar.HangarNumber}");

Console.WriteLine($"Inserting a new airplane");
hangar.Airplanes.Add(new Airplane
{
    TailNumber = "ABC123",
    MaxAirSpeed = 300,
    RunsOnJetFuel = true
});
db.SaveChanges();

var airplane = db.Airplanes
    .OrderBy(a => a.Id)
    .Last();
Console.WriteLine($"Just created airplane: {airplane.TailNumber} in hangar: {hangar.HangarNumber}");

We’ve included queries to check that our entities are saved to the database, and we print the output:

InsertingĀ aĀ newĀ hangar
Just created hangar: HANGAR_01
Inserting a new airplane
Just created airplane: ABC123 in hangar: HANGAR_01

Add a New Migration

Database schemas often change as our project evolves. Let’s make some changes to the entity model and scaffold a new migration to update the database. We’ll add a new property HasDoors to our Hangar class:

public class Hangar
{
    ...

    public bool HasDoors { get; set; }

    ...
}

Then we’ll use the dotnet CLI to apply the new migration to the database:

dotnet ef migrations add Hangar_HasDoors
dotnet ef database update

Our Migrations folder now has a second migration. We’ve also applied those changes to the database schema.

Make Changes to an Existing Migration

Now, for the fun part. Let’s say we find something wrong with the migration we just created. We can make another change and create a third migration, but that’s going to make our migration history messy. Instead, it will be better to remove it and create a new, correct one. If we hadn’t already updated the database schema, we could just remove it:Ā 

dotnet ef migrations remove

But, no! We’re not allowed to remove this migration because it has already been applied to the schema:

The migration '20231209231131_Hangar_HasDoors' has already been applied to the database. Revert it and try again.
If the migration has been applied to other databases, consider reverting its changes using a new migration instead.

Revert a Migration Already Applied

The good news is, there’s an easy way to deal with this. EF Core allows us to revert one or more migrations by running the database update command targeting an earlier migration:

dotnet ef database update Init

The key here is specifying the target migration “Init” so that EF will roll back any later migrations:

Reverting migration '20231209231131_Hangar_HasDoors'.
Done.

Then we will remove the last migration:

dotnet ef migrations remove

Removing migration '20231209231131_Hangar_HasDoors'.
Reverting the model snapshot.
Done.

It’s also possible to revert to an even earlier migration and then runĀ dotnet ef migrations remove multiple times to remove more than one migration.

That’s it! Once we’ve removed the faulty migration, we can make changes to our model and add a new migration to replace it.

Conclusion

In this article, we learned how to revert a migration that has already been applied to the database. We must first callĀ dotnet ef database update targeting a previous migration. Once we’ve reverted the migration, we can safely remove it by callingĀ dotnet ef migrations remove.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!