Database initializers in EF code-first
Published: 2/1/2013 7:32:26 PM
When working with code-first development in entity framework you will most likely need to initialize the database at some point. Entity framework provides a set of database initializers that can be useful in different situations. In this post I will describe the initializers I normally use and when I use them, along with some sample code.
The example code uses an extremely simplified entity that represents a person. The person has a unique id (primary key) and a name:
public class Person
{
[Key]
public int Id { get; private set; }
public string Name { get; set; }
}
The Person entity is part of a DbContext named PersonContext:
public class PersonContext : DbContext
{
public DbSet<Person> Persons { get; set; }
}
To set the database initializer, the Database.SetInitializer() method is used. The following sections will demonstrate how this method can be used, depending on your requirements. For simplicity, it has been assumed that no seeding of the database is required.
CreateDatabaseIfNotExists<DbContext>
This is the default initializer, and does exactly what it says: the database will be created if it does not exist. I normally only use this initializer the first time I run my application, to see if the database connection string works. To use this initializer in code, create an instance of it using your context as the generic type and pass it to SetInitializer():
Database.SetInitializer(new CreateDatabaseIfNotExists<PersonContext>());
DropCreateDatabaseAlways<DbContext>
This initializer will always drop and re-create the database. Any changes to the data in the database will be lost the next time you execute your application. I find this initializer to be useful in the early stages of the development of new applications, when the data model are still unstable and experimental. To use this initializer in code, create an instance of it using your context as the generic type and pass it to SetInitializer():
Database.SetInitializer(new DropCreateDatabaseAlways<PersonContext>());
DropCreateDatabaseIfModelChanges<DbContext>
This initializer will drop and re-create the database, but only if the model changes in any way. This means that as long as you don't modify the model all changes to the data in the database will be preserved between application starts. I use this initializer when the model are stable and I don't expect it to change often. To use this initializer in code, create an instance of it using your context as the generic type and pass it to SetInitializer():
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<PersonContext>());
MigrateDatabaseToLatestVersion<DbContext, DbMigrationsConfiguration>
This initializer will attempt to migrate model changes into the current database. This means that existing data will be preserved (if possible) when the model changes, which is in most cases a requirement for production environments. Once an application goes live (leaves the development/testing stage and enters production stage) I switch to this initializer.
Notice that this initializer requires two generic types: a DbContext and a DbMigrationsConfiguration. The latter type can be used to specify how the migration will behave when data may be lossed. For example, to specify that data loss is not acceptable during the migration, create a class that inherits from DbMigrationsConfiguration and set AutomaticMigrationDataLossAllowed to false, like this:
public class MigrationConfiguration : DbMigrationsConfiguration<PersonContext>
{
public MigrationConfiguration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
}
}
The class is then passed as the second generic type to the MigrateDatabaseToLatestVersion initializer:
Database.SetInitializer(
new MigrateDatabaseToLatestVersion<PersonContext, MigrationConfiguration>());