Automatic migrations with NHibernate
A few weeks ago, we published a blog post on how to configure automatic migrations with Entity Framework. Here's the opening quote from that article on why you should care about automatic migrations (read the rest of the article here):
Having your application automatically update its database schema greatly eases development and makes frequent deployments to platforms like AppHarbor a cinch.
The main AppHarbor codebase actually uses NHibernate and Fluent NHibernate augmented with EventStore CQRS. Our NHibernate setup is configured to automatically update the database schema as we push updates to our model classes. To do this, we use a little-published feature of NHibernate called SchemaUpdate
. In conjunction with Fluent NHibernate, this can be used to create SessionFactories in the following way (this example is for PostgreSQL):
protected ISessionFactory CreateSessionFactory()
{
var connectionString = "connectionString";
var autoMap = AutoMap.AssemblyOf<Entity>()
.Where(t => typeof(Entity).IsAssignableFrom(t));
return Fluently.Configure()
.Database(
PostgreSQLConfiguration.Standard.ConnectionString(connectionString))
.Mappings(m => m.AutoMappings.Add(autoMap))
.ExposeConfiguration(TreatConfiguration)
.BuildSessionFactory();
}
protected virtual void TreatConfiguration(NHConfig.Configuration configuration)
{
var update = new SchemaUpdate(configuration);
update.Execute(false, true);
}
Also note that we us AutoMap
to create schema only for all classes that inherit from Entity
. We can use the code above in conjunction with an IoC container like StructureMap and ASP.NET like this:
ObjectFactory.Initialize(x =>
{
x.For<ISessionFactory>()
.Singleton()
.Use(CreateSessionFactory());
x.For<ISession>()
.HttpContextScoped()
.Use(context => context.GetInstance<ISessionFactory>().OpenSession());
});
With this configuration, whenever a new ISessionFactory
is created, the running schema is compared with schema dictated by the model classes (here all classes inherited from Entity
) and the running schema is updated as needed. Our SessionFactory is a singleton, so this process will only happen when the application is restarted.
We have been running with a setup like this on AppHarbor since the very first model class was created. Once in a while we have to plan manual schema- or data-migrations, but for for the most part this simple setup quietly syncs our database with our model every time new we push new versions of AppHarbor.
If you want to see how this works in the context of an ASP.NET MVC application then check out this sample we've published for using some of the PostgreSQL-compatible add-ons we offer. It uses the above setup in a simple ASP.NET MVC 3 application that will automatically configure its database the first time it's deployed and keep it updated as the application model is expanded.