For my next post, I’m planning to review a really solid Ruby on Rails book I’ve been reading. In that book, I once again encountered the Ruby database migrations project. I’d come across a .NET port a while back, but was led to believe it was very much in progress. I decided to Google it again and sure enough the port is being actively maintained with recent commits.

If you’re not familiar with the migrations, the basic idea is as follows. Create a class (a migration) that represents a change to your database. A migration class could do anything from creating a table to adding a unique constraint. Again, it’s just an abstraction of a change to your database. Each migration is versioned with a timestamp (long int). When the migration task runs, it runs all migrations with version numbers higher than the last saved version (stored in a schema_info table that is added to your database). Rolling back is as simple as running the task with a specified version number.

As an example, the class below implements Up and Down. Up adds an Album table and creates a foreign key to Artist. Down drops the table (executed when a lower version number is specified during task execution).

[Migration(20090210125154)]
public class AddAlbumTable : Migration {

    public override void Up() {

        Database.AddTable("Album",
            new Column("AlbumID", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity),
            new Column("AlbumName", DbType.String, ColumnProperty.NotNull),
            new Column("ArtistID", DbType.Int32, ColumnProperty.NotNull));

        Database.AddForeignKey("FK_Album_Artist", "Album", "ArtistID", "Artist", "ArtistID")

    }

    public override void Down() {
        Database.RemoveTable("Album");
    }
}

A NAnt task comes with the DotNetMigrations project. Configure it like:

<?xml version="1.0" encoding="utf-8"?>

<project name="LongTailDBMigrations" basedir="." default="migrate">

  <loadtasks assembly="bin/Debug/Migrator.NAnt.dll" />
  <target name="migrate" description="Migrate the database">
    <property name="version" value="-1" overwrite="false" />
    <migrate
      provider="SqlServer"
      connectionstring="Data Source=SERVER;UID=USER;PWD=PASSWORD;DATABASE=DBNAME;"
      migrations="bin/Debug/YourMigrations.dll"
      to="${version}" />
  </target>

</project> 

Finally, run the command:

nant migrate

or to a specific version

nant migrate -D:version=20090207031810

The MigratorDotNet project is located here.