A few weeks ago Rob Conery foolishly tapped me to help get migrations in SubSonic up to snuff and I've been working on them ever since trying to sneak them into the latest SubSonic beta.  I've changed the way they're implemented slightly from when Rob first talked about them so here's a quick re-introduction to migrations.

Migrations are a way to create and version your database schema using code rather than having to rely on SQL scripts or compare and sync tools.  They allow you to quickly rollback schema changes as well migrate schema changes from your development database to staging and then on to production.  In a nutshell they rock when it comes to database maintaince, versioning and deployment.

Migration Breakdown

A migration is a class that descends from SubSonic.Migration and overrides both the Up() and Down() methods.  Up() is used when going up a version and Down() is used to restore the database schema to the pre-Up() state.  Anything you do in the Up() should be undone in your Down(). 

By convention they are put in a Migrations folder off the root of your project folder.  While the actual name of the class isn't important the name of the file is critical because this is how SubSonic determines which version the migration represents.  The naming convention is 000_MigrationName.cs (or .vb) with the version number represented by leading three numerics, starting at '001' and working your way up.  Currently it's pretty particular about that naming convention so make sure it's exactly three numerics, padded with zeros if needed.  It's convention to name your migration file something descriptive and to also not repeat names, such as:

001_AddExerciseTable.cs

An Example

Let's start with a simple example and break it down:

using System;
using System.Collections.Generic;
using System.Text;
using SubSonic;

namespace SubSonic {
  public class Migration001:Migration {

    public override void Up() {
      TableSchema.Table t = CreateTable("Flights");
      t.AddColumn("Name", System.Data.DbType.String);
      t.AddColumn("FlightNumber", System.Data.DbType.String, 100);
      t.AddColumn("DateTraveling", System.Data.DbType.DateTime, 0, false, "getdate()"); 
      AddSubSonicStateColumns(t);
    }
  
    public override void Down() {
      DropTable("Flights");
    }
  }
}

In the example the 'Flights' table is created, then three columns are added to it, followed by the standard SubSonic state columns.  If you don't specify a primary key one will be created for you with the pattern of 'TableNameID', so that's one less thing to worry about.  The Down() method undoes everything we did in the Up() by dropping the 'Flights' table.

Available Methods

Currently the methods available from inside your migration are:

  • CreateTable(string tableName) - This creates and returns a table schema to which you can add your columns, as seen in the example.
  • DropTable(string tableName) - Does exactly what it says.  If your Up() has a CreateTable() you'll need a corresponding DropTable().
  • AddColumn(string tableName, string columnName, ...) - Used to add a new column to an existing table.  It has all the same overloads as TableSchema.Table.AddColumn() except the first parameter is the name of the table you'll be adding columns to.
  • RemoveColumn(string tableName, string columnName) - You only get one guess that this does :)
  • AlterColumn(string tableName, string columnName, ...) - Used to alter an existing column, again, the same overloads as AddColumn.
  • AddSubSonicStateColumns(TableSchema.Table table) - Adds the conventional SubSonic state columns to your table.  I'll be adding another overload that just takes a tableName if you want to add those columns to an existing table.

Running your Migrations

To run your migrations you'll use SubCommander, the same tool used to generate your models but with the 'migrate' command.  The simplest usage is:

sonic migrate

That's it.  It'll use your default provider, look for your migrations in <project>\Migrations and run every migration Up() starting at your database's current migration up the last one found in the Migrations folder.  You can also specify the provider, migration directory and version at the command line like this:

sonic migrate /provider "Northwind" /migrationDirectory "D:\Testing\Migrations" /version 4

A few things to remember:

  • Migrations by convention are looked for in a \Migrations folder off the root of your project, though this can be changed via the command line. (/migrationDirectory "D:\Migrations")
  • You run a migration against a single provider at a time, there is no support for specifying the provider inside the migration.  The main reason is portability, often you'll be running this migrations against different databases and hardcoding the provider name in the migration destroys their usefulness.
  • Migrations will run against the default provider unless otherwise specified via the command line (/provider "Northwind")
  • By default migrations will try to go up to the latest version found in the migrations folder.   To go up or down to a specific version use /version X to indicate which version.
  • To enable migration support a new table 'SubSonicSchemaInfo' will be created in your database, so don't delete it and tell your DBA that it's OK :)

TODO

These are things you *should* see before the next beta drop, but don't hold me to it :)

  • Ability to generate your migration code skeleton using sonic.exe.
  • Add RenameTable()
  • Add RenameColumn()
  • Add ability to execute ad-hoc sql, for creating stored procs, views, creating roles, users, etc.
  • Add constraints
  • Add foreign keys

2 Comments

I'm a big fan of SubSonic, a ORM/DAL generator slash utility belt of goodness.  Like any tool there is a little configuration and setup you need to do to get everything rolling and while Rob Conery has some great podcasts on doing just this sometimes you just need to remember that one little option vs. wanting to watch a 10 minute podcast again, regardless of how melodic and sweet are the dulcet tones of Mr. Conery's voice.

1. Download and Install SubSonic.

Seems simple but hey, some people need to be told everything :)

2. Create SubSonic DAL as an external tool

Even though SubSonic supports Rails-style auto-gen of your DAL via build providers I like putting my model/DAL in a separate class library and sadly build providers don't play well with class libraries. 

Go to Tools | Externals Tools... click "Add" and make it look like this:

External Tools

  • That command is your path to sonic.exe
  • If you're working with the MVC Toolkit (and why aren't you?) then change "App_Code\Generated" to "Models\Generated"

3. Create SubSonic DB as an external tool

SubSonic can also version and script your database, very useful for source control and distributing your application.  Same as above but make it look like this:

External Tools (2)

4. Install SubSonic Schema

I dislike any warnings during a build and one you'll get with SubSonic is it not knowing about the SubSonic config sections.   I did a blog post on how to fix this awhile back but I'm repeating here for the lazy (like myself):

  1. Download SubSonicSchema.xsd (if you right-click to download make sure you save it with an xsd extension)
  2. Put it in C:\Program Files\Microsoft Visual Studio 8.0\Xml\Schemas (adjust accordingly for VS2008)
  3. Edit DotNetConfig.xsd in the same folder and add the following line:



    (I added it right underneath the <xs:schema> opening tag, seems to work.  Also, if you're using Vista you'll need to edit DotNetConfig.xsd in an editor that was started with right-click, Admin, otherwise it'll write a copy of the xsd into the Virutal Store and your changes will never take effect.  Trust me, I learned this the hard way.)




  4. Close Visual Studio if it's running, re-open, ta-da you now have IntelliSense as well as no more annoying "Could not find schema information for..." messages.


5. Install SubSonic code snippets



You add various sections into your web.config to wire up the magic and nothing is more boring than typing the same poop over and over again.  I created some snippets that provide the various bits that you can download here (actually not quite yet since the bits are at work and my VPN is broken right now).



And Bob's your Uncle, you have all the boring schtuff out of the way and now you're ready to start genning ya some code.  If you don't actually know how to start genning your code then I'd suggest watching some of those screencasts I mentioned above.

3 Comments

I've been dabbling in the Ruby on Rails world for awhile and I've always been drawn to the very clean separation of the Model-View-Controller framework, something Rails pretty much nailed in their implementation.  I've done a few small Rails sites here and there, played with it enough to be dangerous but I didn't use it enough in my daily life to really get it under my belt.  At the same time I was doing a lot of ASP.NET work and felt like I was constantly fighting the WebForms architecture to get it to produce proper stateless standards-compliant web applications that were based around the concept of request/response.  I'd disable ViewState, override Inits(), hack into the page lifecycle and ignore server controls so I had real control the HTML output and get back my CSS id selectors.  In a very bad way WebForms reminded me of VB6 and all the hacks I had to do during my stint with that language.

The most frustrating point came when the CSS Adapters were released and touted as some kind of panacea to those that cared about web standards when in reality they are more akin to giving a woman with a horrible breast job a big baggy sweater with a picture of a nice rack on the front.  Sure, it may be a pretty picture but the scar tissue and ugly layers are still there.

I think I got some of my faith back after I started reading Rob Conery's blog because in him I found a Rails enthusiast who still enjoyed the many good aspects of ASP.NET and C#.  Instead of just jumping ship he was bringing some of the better elements, and more importantly concepts, over to the .NET side with the SubSonic project.  Then he somehow got mixed up with some other crazy people like Phil Haack, Scott Guthrie and Scott Hanselman and now we have the ASP.NET 3.5 Extensions Preview which contains a juicy little nugget otherwise known as ASP.NET MVC.

After wading through the bits, doing a few sample projects and generally taking their version of MVC for a walk-about I can say I'm once again excited about .NET.  Sure there are some rough spots and some areas that are a bit too "chewy" (you know a line of code that's a 100 characters long and includes at least three generics and two type casts?  yeah, that's chewy) and design decisions that some people are taking umbrage over but all in all it feels useful, feels clean and feels like real programming.

In an odd way I have the same feeling I had back in the day when I switched from Visual Basic to Delphi (which I still think is the best tool for creating native Win32 applications), like I once again have control.

3 Comments

Designed by Free CSS Templates. | Sign in