How to Update Your Database Structure in Entity Framework
Using Code First with Entity Framework, EF will create a database for you based on your domain models. But how do you control when and how the database will be created, and how the structure is updated?
Entity Framework 6.x includes a range of database initializers that specify how and when EF should generate a new database. These database initializers are intended to be used in different stages of the development process. By default, Entity Framework will create a database only if one does not already exist using the CreateDatabaseIfNotExists
class. However, during development Entity Framework can be configured to drop and recreate the database every time there’s a schema change.
Note: In this post I cover how to use database initializers with Entity Framework 6.x in an ASP.NET project. Entity Framework Core doesn’t include database initializer classes.
Drop and Recreate Your Database
During the development process, the domain models will be changing often. You can configure Entity Framework to delete (drop) and recreate your database every time there is a change to your schema.
To do this, you need to create an initializer class in the same folder as your DbContext
class. The class needs to inherit from DropCreateDatabaseIfModelChanges
.
public class YourInitializer: System.Data.Entity
.DropCreateDatabaseIfModelChanges<YourDbContext>
{
// Seed Method
// ...
}
To tell Entity Framework to use your initializer class, add an element to the entityFramework
element in the application Web.config
file (this should be in the root of your project folder):
<entityFramework>
<contexts>
<context type="Namespace.YourDbContext, ProjectName">
<databaseInitializer type="Namespace.YourInitializer, ProjectName" />
</context>
</contexts>
...
Creating a Seed
method
The Database initializer classes include a Seed
method that you can override. EF will automatically call this method after recreating the database to populate it with data.
For example:
public class MyInitializer : System.Data.Entity
.DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(MyContext context)
{
var students = new List<Student>
{
new Student{FirstMidName="Carson",EnrollmentDate=DateTime.Parse("2005-09-01")},
new Student{FirstMidName="Meredith",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Yan", EnrollmentDate=DateTime.Parse("2002-09-01")}
};
students.ForEach(s => context.Students.Add(s));
context.SaveChanges();
//...
Testing
There is also a DropCreateDatabaseAlways
initializer class you can use to drop and recreate your database every time your application runs. This is useful during the testing stage.
Using Migrations
Once your database is ready for production, none of the above database initializers are going to be suitable for use. If you want to make changes to a database in production, you don’t want to drop the entire database and lose all of the data. Code First Migrations allow you to update your database structure without having to drop and re-create the database.
To install the Migration package, click:
Tools
Nuget Package Manager
Package Manager Console
and type:
Enable-Migrations
You will need only three CLI commands to use Migrations in your ASP.NET EF project.
Command | Description |
---|---|
Enable-Migrations |
Install migration modules - this only needs to be run once initially |
Add-Migration [MigrationName] |
Generate a new migration code file based on changes in your project models |
Update-Database |
Implement any outstanding migrations |
Migration Files
Migrations are code files. Every time you run Add-Migration
a code file is generated, usually in a folder called Migrations
inside your project. The name of a migration file is composed with a timestamp of its generation concatenated with the name used when running Add-Migration
. For example:
Add-Migration Initial
generates
201710021217244_Initial.cs
You can check the contents of those files and see the generated migration file. You can also modify them like any other code file.
It’s useful to think of migrations as git commits for your database. They document changes to your schema over time, and each migration builds on the last. Like git commits, you should be able to revert to any specific migration if necessary. Over time, your migrations folder will look something like this:
Migrations
│ Configuration.cs
│ 201801170953558_initial.cs
│ 201802041312365_transactions-added.cs
│ 201802041329270_transaction-additional-fields.cs
│ 201802042308138_transaction-added-as-navigation-property.cs
│ 201802111402054_purchased-added-to-transaction-type.cs
└───SeedData
In addition to the Migration code files, EF creates a table in your database called __MigrationsHistory
that contains information about all of the migrations that have been run in your database.
Up and Down Methods
Every migration file has an Up
method and a Down
method. The Up
method updates the database. The Down
method reverts them. Here’s a simple change as an example:
namespace Project.Migrations
{
public partial class TransactionModelUpdated : DbMigration
{
public override void Up()
// Contains the code to implement the changes
{
AddColumn("dbo.Transaction", "Note", c => c.String());
}
public override void Down()
// Contains the code to undo the changes
{
DropColumn("dbo.Transaction", "Note");
}
}
}
The Down
method is invoked with:
Remove-Migration [options]
However, in reality you will probably never have to use this.
I have never needed the ‘undo’ a migration command, and a quick survey of EF users at a recent talk I gave came back with the answer that none of them had ever used the ‘undo’ migration commands either. – Jon P Smith, Entity Framework Core in Action
The Configuration File
There is a configuration class for EF Migrations called DbMigrationsConfiguration
class. This configuration class is automatically generated with the Enable-Migrations
command. You can find it in the Migrations folder:
internal sealed partial class Configuration :
DbMigrationsConfiguration<ProjectName.DAL.DBContextName>
{
This class has its own Seed
method that will run every time the Update-Database
command is executed, even if there is no explicit pending migration.
Before using the Migrations Seed method, you’ll need to disable the database initializer by commenting out or deleting the <databaseInitializer>
element you added in the Web.config
file.
Since we are no longer dropping and recreating the database, the Migrations Seed
method must be able handle the data already contained in the database. There is an extension method, AddOrUpdate
, that is specifically designed for this purpose.
protected override void Seed(ProjectName.DAL.DBContextName context)
{
context.Students.AddOrUpdate(
s => s.LastName,
new Student { StudentID = 12345678,
FirstMidName="Carson", LastName="Arturo" }, );
}
Instead of loading data into the database, AddOrUpdate
will only add the entry if it doesn’t currently exist in the database. If the entry doesn’t match the new database schema, it will update accordingly.
It’s important to note that you will need all of the fields for your record when you are using AddOrUpdate
. For example, if the above record already exists in the database, but also included an EmailAddress
field carson.arturo@email.com
, this would be set to null in the update, since it wasn’t provided to the AddOrUpdate
method.
Julie Lerman (One of the creators of Entity Framework) writes more about AddOrUpdate
more here.