Back to all posts

Renaming Tables Safely in Entity Framework Core

Posted on Nov 30, 2021

Posted in category:
Development
Entity Framework

I have long embraced the usage of Entity Framework Migrations and the many things it can do to help me. I have also been getting by for years using the basic "standards-based" naming conventions, making things quick and easy. However, there is one situation that the standard conventions do not handle well, and that is the renaming of a table. The default behavior is to drop the table and re-create it. I don't know about you, but that doesn't work for me about 99.9% of the time. So how do we get around this?

The Standard Practice

Let us start by covering the standard practice for how a DbContext might be configured with a table, combined into a single snippet for brevity.

Standard Convention Based DbContext
public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions options)
        : base(options)
    {
    }

    public DbSet Widgets { get; set; }
}

public class Widget
{
    public int WidgetId { get; set; }

    [StringLength(100)]
    public string WidgetName { get; set; }
}
    

In this example, if you create a migration, it will add a table for you called Widgets, and that table will have the proper PrimaryKey column of WidgetId, all based on convention. Awesome, and you can add columns as you need, etc., with relative ease, but this is where the easy part goes.

Renaming the Table

Based on the fact that we can add tables, add columns, and even modify attributes of columns easily; one would think we could simply rename our object using our lovely Rename refactoring within Visual Studio and move on, right? Wrong!

Default Behavior of Rename

The benefit or drawback, depending on how you look at it is that the structure and names of your code define the model. You are not adding any metadata or attributes to control this. So, if we rename Widget to Car and attempt to create a migration, we will see that the generated migration will drop the Widget table and add a new Car table. You can imagine how complicated this can be if you have foreign keys or other relationships.

So how do we work around this?

Data Annotations/Fluent Sytax to the Rescue

One method to get around this is to temporarily utilize Data Annotations to guide Entity Framework with what you would like to do; then, after creating a proper migration, you can rename the objects properly and create a blank migration to finalize the change. This allows you to address the issue at hand, renaming, while still keeping the convention based model for long-term support..

Let us explore the method of renaming Widget to Car using the sample code from above. First, we will use a combination of Annotations and Fluent Syntax to complete the first migration step.

Code For Intermediate Rename
public class ApplicationDbContext : IdentityDbContext
{
    public DbSet Widgets { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        //Perform the base configuration items, we do our stuff AFTER so we can configure it
        base.OnModelCreating(builder);

        //Temporary Rename
        builder.Entity().ToTable("Cars").HasKey(k => k.CarId);
    }
}
public class Widget
{
    public int CarId { get; set; }

    [Column("CarName")]
    [StringLength(100)]
    public string WidgetName { get; set; }
}
    

The above code snippets introduce two key concepts. The first is the usage of the fluent syntax to tell the builder that `Widget` should map to the table Cars, and it has a specific primary key column (which you can see we renamed.) With this change in place, we can create a new migration, which will result in a rename of the table, the primary key, and any associated indexes.

Once this is completed, we can update the code to the following.

Code for Going Forward
    public class ApplicationDbContext : IdentityDbContext
    {
        public DbSet Cars { get; set; }
    }
    public class Car
    {
        public int CarId { get; set; }

        [StringLength(100)]
        public string CarName { get; set; }
    }
    

As you can see, this code is as you would expect without any of the additional fluff and matches conventions exactly. It is important that at this stage, you create a NEW migration. This migration, if done successfully, should have NO documented changes, but the DbSnapshot that is managed internally must be updated properly.

In Conclusion

Convention-based model management with Entity Framework is possible and results in a lot less code, most of the time. However, with any feature, there are drawbacks, and the ability to rename/restructure your data model is one of the items that are "less fun" using conventions. Others might argue for a different configuration process, which has its own benefits and drawbacks, but I hope this has helped you in your operations with EF Migrations.