Saturday, December 8, 2012

Recreating a Dropped Database in Entity 5

I've been working on a windows service that constantly monitors a local database. One of the responsibilities of the service is to create and seed the database if it doesn't already exist. This was necessary because the database may be dropped at anytime within the system, and it needs to be recreated quickly. With Entity Framework 4.3 and no migration support, the following code achieved that.

if (!context.Database.Exists())
{
    context.Database.Create();
    _Seed(context);
    context.SaveChanges();
}

New specifications for this system required support database migrations, so I took the opportunity to upgrade the code to use Entity Framework 5. Without going into the details of how EF 5 migrations work, I'll just say that I enabled migrations and I'm now using the Configuration class to handle seeding by overriding the Seed(context) method.

To handle the migrations, I opted to use the MigrateDatabaseToLatestVersion initializer provided in the framework. This initializer executes any missing migrations to get the database current.

Entity.Database.SetInitializer<DatabaseContext>(
    new MigrateDatabaseToLatestVersion<DatabaseContext, Migrations.Configuration>());

After these changes, I simplified the database check and creation process to the following

if (!context.Database.Exists())
{
    context.Database.Initialize(true);
}

What I found was this works fine when no database exists and the service is started, but it no longer works properly when the database is dropped during the runtime of the service. The Exists check properly returns false, but the Initialize method call does not actually create the database. I'm passing true as the argument, which should force the initializer to run. So what's going on here? From what I can tell, the instance of MigrateDatabaseToLatestVersion will only create a database once. To work around this, I create a new instance of the initializer whenever the database doesn't exist.

if (!context.Database.Exists())
{
    Entity.Database.SetInitializer<Database.DatabaseContext>(
        new MigrateDatabaseToLatestVersion<Database.DatabaseContext, Migrations.Configuration>());
    context.Database.Initialize(true);
}
else
{
    context.Database.Initialize(false);
}

The database is now properly recreated when it no longer exists.