Como gerenciar versões de banco de dados - Parte 2

Comments
migrations migrator.net
08 March 2009

Na primeira parte falei um pouco dos problemas envolvidos no controle de versionamento de banco de dados. Agora esta na hora de apresentar alguma solução, certo? :)

Apresentando Migrator.NET

Para resolver a maioria (senão todos) os problemas de versionamento de banco temos uma ferramenta maravilhosa chamada Migrator.NET. Essa ferramenta é um port para .NET do original em Rails. A idéia por trás dela é bastante simples: consiste em diversos objetos (classes) versionados (da mesma maneira que código normal) contendo as instruções que devem ser executadas para gerar e/ou voltar o schema do banco de dados. Cada classe corresponde a uma instrução de alteração e contém um método Up (adicionar/avançar) e um método Down (retroceder/fallback) equivalente. Vejamos como é facil no exemplo abaixo:

#region Usings

using System.Data;
using Migrator.Framework;

#endregion

namespace NetScrum.Migrations.Tables
{
    [Migration(20090209211900)]
    public class CreateTableProject : Migration
    {
        public override void Down()
        {
            Database.RemoveTable("netscrum_project");
        }

        public override void Up()
        {
            Database.AddTable("netscrum_project",
                new Column("id", DbType.Int32, ColumnProperty.Identity)
                , new Column("name", DbType.AnsiString, 100, ColumnProperty.NotNull)
                , new Column("description", DbType.AnsiString, 300, ColumnProperty.Null)
                );

            Database.AddPrimaryKey("pk_project", "netscrum_project", "id");
        }
    }
}

Viram? Basta referenciar a DLL Migrator.Framework.dll, adicionar a diretiva using criar sua classe herdando de Migration e dar override nos métodos Up e Down.

Gerenciando as versões

Para gerenciar as versões e garantir que os migrations sejam executados na ordem correta, você deve utilizar o atributo Migration(long version) decorando a classe. Você deve preenche-lo com um long contendo o timestamp no formato AAMMDDhhmmss (ano/mes/dia/hora/minuto/segundo) em que seu migration foi gerado. Ou seja, um alter table da tabela projeto, por exemplo, deve conter um valor mais novo (maior) que o create table correspondente para que o migration de create seja executado antes do alter.

Configurando o build

Criar e gerenciar migrations é muito fácil. No entanto, as configurações dele são um pouquinho chatas para quem não está familizarizado com MSBuild ou NAnt. Neste artigo vamos usar o MSBuild que já é nativo e eu gosto mais simplesmente por estar familiarizado.

Junto com o código fonte compilado do Migrator.NET vem também o assembly Migrator.MSBuild.dll que é onde está a o target especifico que o MSBuild precisa para executar os migrations. Este target será usado no arquivo de build (explicado mais abaixo) e deve ser configurado como o exemplo abaixo apontando para o caminho onde esta o assembly. Arquivos Migrator.Targets:

 $(MigratorTasksPath)\Migrator.MSBuild.dll

A propriedade $(MigratorTasksPath) define onde está o assembly Migrator.MSBuild.dll. O valor desta propriedade pode ser hard-coded ou então preenchida no arquivo de build conforme veremos.

Por padrão, todo projeto (arquivo.csproj no caso de C#) é um arquivo de MSBuild. É possível editá-lo para incluir as configurações necessárias ao Migrations, mas cedo ou tarde é perigoso que Visual Studio o recrie ou o modifique a seu bel prazer e ai perderiamos as customizações. Portanto, prefiro criar um outro arquivo de build exclusivo para os migrations e chama-lo quando eu bem entender. Segue abaixo o arquivo NetScrum.Migrations.build:

 $(MSBuildProjectDirectory)

Este arquivo define uma série de paramêtros:

  • MigratorTasksPath - Caminho utilizado para apontar onde esta o target (mencionado acima). Neste caso, é preenchido pela propriedade $(MSBuildProjectDirectory) que aponta para onde o arquivo build que está sendo chamado está localizado.

  • DatabaseVersion - Será passado via paramêtro na hora da chamada do Migrator.NET. Caso não seja informado, o valor default é -1 que indica para a última versão.

  • Provider = Banco de dados de destino. Neste caso estamos usando SqlServer, mas Migrator.NET funciona para outros bancos também.

  • Connectionstring - Óbvio, né? :)

  • To - Recebe o valor do parametro DatabaseVersion indicando a versão de destino do migrations.

  • Migrations - Caminho onde se encontra o assembly compilado contendo as migrations.

Existem alguns outros paramêtros que permitem uma configuração um pouco diferenciada, como por exemplo, ao invés de fornecer o assembly compilado apenas informar o caminho onde estão as classes para que o próprio Migrator.NET faça a compilação.

Uma vez que tudo esteja configurado, basta ir até o command prompt, navegar até a pasta onde o arquivo.build e chamar o MSBuild passando os paramêtros conforme o exemplo abaixo:

%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe NetScrum.Migrations.build /t:Migrate /p:DatabaseVersion=-1

Os paramêtros são:

  • NetScrum.Migrations.build - Nome do arquivo de build que contém as configurações do Migrator.NET

  • /t:Migrate - Target que deve ser executado. Neste caso o target de migrations :)

  • /p:DatabaseVersion=-1 - Versão do banco para qual desejo ir. Caso queira ir para última versão é só informar -1. Caso queira zerar o banco (executar Down de todas as migrations) é só informar 0. No caso de ir para uma versão específica é só informar o timestamp desejado.

É isso! Configurar a primeira vez é um pouco chato. Acertar os caminhos dos arquivo requer algumas tentativas para quem não está familizarizado com o MSBuild, mas nada muito traumático. Nos exemplos, todos os arquivos necessários (menos o assembly contendo as migrations) estavam na mesma pasta (tools) para facilitar.

Exemplo

Quem quiser ver o exemplo funcionando, basta baixar a última versão do .NET Scrum. Ele contém as pastas e arquivos configurados direitinho pra funcionar.

Importante

A versão utilizada para este artigo foi a 0.8 que baixei tem uns 45 dias. Na época, apesar de compilada não estava funcionando então tive que efetuar umas pequenas correções do trunk. Não testei a versão 0.8 disponível hoje, portanto você pode baixar aqui a versão 0.8 compilada e corrigida por mim.

Referências

Até alguns dias atrás eu não tinha encontrado nenhum outro artigo a respeito deste assunto em português. Acredito que ainda não exista e esse seja o primeiro. Além das instruções básicas de banco que foram apresentadas no migration do exemplo ainda é possível criar PKs, FKs, executar Sql's open text entre outros procedimentos não descritos aqui.

Vocês podem encontrar informações a respeito desses procedimentos no site do projeto ou tirar dúvidas e perguntar aqui mesmo no blog.

Enjoy!


<< Pai Rico, Pai Pobre: Resenha
Pré venda, negociação e propostas em Modelo Ágil. Como fazer?>> 
comments powered by Disqus
tucaz

tucaz

.NET Software Developer
About
All Posts
RSS
@tucaz
GitHub