I'm using TFS Release Management to do continuous integration and deployment.
I'm using migrate.exe to perform the database migration during deployment, and this works great when you're going from an older version to a newer version. When you want to deploy an older version of the application, however, it gets more muddy.
Basically, the assembly that holds your migrations for a context must know how to go from say version 3 to version 2. Normally, you use the assemblies you're about to deploy as the source of your migrations, but in this case, you must use the already deployed assemblies as they're the only ones who know how to get from v3 down to v2. (Version 2 has no idea that v3 even exists.)
My current plan is to somehow compare the two assemblies during deployment. If the assembly in the installation directory contains "newer" migrations than the one in the deployment director, I would first need to get the "newest" available migration in the assembly in the deployment directory, and then execute:
migrate.exe AssemblyInInstallationDir /targetMigration NewestFromAssemblyInDeploymentDir
Where as in a "normal" deployment scenario where you are upgrading to a newer version, you can just do:
migrate.exe AssemblyInDeploymentDir
Is this a legit approach? I have yet to look into using EF libraries to evaluate what migrations are available in each assembly. There is also the challenge of the fact that each of these assemblies are the "same" just different versions. I'll probably have to load them into separate app domains and then use cross-app domain communications to get the information I need.
EDIT
I created a proof of concept app that allows me to list the available migrations to two different versions of the same assembly. This was critical to this entire process, so I figured it's worth documenting.
The app uses reflection to load each of the assemblies and then uses the DbMigrator class from System.Data.Entity.Migrations to enumerate the migration meta data. The names of the migrations are prefixed with the timestamp information, thereby allowing me to order them and see which assembly contains the "newer" set of migrations.
static void Main(string[] args)
{
const string dllName = "Test.Data.dll";
var assemblyCurrent = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Current\\{0}", dllName)));
var assemblyTarget = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Target\\{0}", dllName)));
Console.WriteLine("Curent Version: " + assemblyCurrent.FullName);
Console.WriteLine("Target Version: " + assemblyTarget.FullName);
const string contextName = "Test.Data.TestContext";
const string migrationsNamespace = "Test.Data.Migrations";
var currentContext = assemblyCurrent.CreateInstance(contextName);
var targetContext = assemblyTarget.CreateInstance(contextName);
var currentContextConfig = new DbMigrationsConfiguration
{
MigrationsAssembly = assemblyCurrent,
ContextType = currentContext.GetType(),
MigrationsNamespace = migrationsNamespace
};
var targetContextConfig = new DbMigrationsConfiguration
{
MigrationsAssembly = assemblyTarget,
ContextType = targetContext.GetType(),
MigrationsNamespace = migrationsNamespace
};
var migrator = new DbMigrator(currentContextConfig);
var localMigrations = migrator.GetLocalMigrations(); //all migrations
Console.WriteLine("Current Context Migrations:");
foreach (var m in localMigrations)
{
Console.WriteLine("\t{0}", m);
}
migrator = new DbMigrator(targetContextConfig);
localMigrations = migrator.GetLocalMigrations(); //all migrations
Console.WriteLine("Target Context Migrations:");
foreach (var m in localMigrations)
{
Console.WriteLine("\t{0}", m);
}
Console.ReadKey();
}
}
The output of the application looks like:
Curent Version: Test.Data, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null
Target Version: Test.Data, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null
Current Context Migrations:
201403171700348_InitalCreate
201403171701519_AddedAddresInfoToCustomer
201403171718277_RemovedStateEntity
201403171754275_MoveAddressInformationIntoContactInfo
201403181559219_NotSureWhatIChanged
201403181731525_AddedRowVersionToDomainObjectBase
Target Context Migrations:
201403171700348_InitalCreate
201403171701519_AddedAddresInfoToCustomer
201403171718277_RemovedStateEntity