Olá pessoal.

Estive recentemente analisando algumas opções de gerenciamento de alterações em bases de dados durante o processo de desenvolvimento de um aplicativo. Ou seja, uma forma de controlar a estrutura do banco de dados que estou construindo e de que como garantir a sua distribuição de forma segura e descomplicada.

Para facilitar o entendimento desta necessidade, descrevo abaixo um cenário fictício mas que se aplica ao que quero.

Cenário

Digamos que inicio o desenvolvimento da versão 1.0 de um aplicativo de controle financeiro pessoal. Nesta primeira versão preciso de algumas tabelas, como por exemplo, tabela de Entradas e Saídas. Uma forma tradicional de desenvolver a base é criar a estrutura das tabelas diretamente na base de dados e ao final do processo copiar o script desta base para replicar em outras bases (qualidade, homologação, produção, etc).

Porém ao longo do desenvolvimento criamos uma série de estruturas na base de dados que podem não ser necessários para a versão final do aplicativo, ou seja, criamos alguns lixos na base que não devem ir para uma base de produção.

Como controlar qual estrutura deve ou não ir para uma base de produção? Uma forma seria termos duas bases, uma de desenvolvimento e outra que representa a oficial. Neste caso, após concluir o desenvolvimento eu teria que replicar as alterações que realmente preciso na base oficial e a partir desta base então gerar o script que irá para produção. Este modo funciona mas é sujeito a erros, pois posso esquecer de replicar algum detalhe que só vou descobrir em uma fase de testes ou mesmo já em produção. Isto não é aceitável.

Além disto, depois que liberar oficialmente a versão 1.0, eu inicio o desenvolvimento da versão 2.0 do aplicativo. Sendo assim, agora terei que controlar não apenas a criação das tabelas mas também a alteração delas e possivelmente ajustes nos dados já existentes. Para complicar mais um pouco, posso ter cenários que irei atualizar a base da versão 1.0 para a 2.0, porém pode ocorrer também de estar com uma base 1.0 e precisar atualizar para a 3.0, ou seja, preciso aplicar o script da 2.0 antes da 3.0.

Sendo assim, preciso definir uma forma de gerenciar estas alterações na base de dados de forma segura (sem esquecimentos) e de forma prática permitindo desde uma criação inicial até a atualização de versões futuras.

Opções

Em busca de um recurso nessa linha me deparei com duas boas possibilidades, o Data-Tier Applications e o Code First Migrations.

Data-Tier Applications

O que é?

O Data-Tier Applications (DAC) é um pacote de artefatos que contém todos os objetos de base de dados do aplicativo. O DAC fornece uma forma unificada de definir, distribuir e gerenciar a estrutura de dados de um aplicativo ao longo de toda a vida de desenvolvimento de um aplicativo (criação e manutenção). Além disto, permite uma melhor comunicação entre os desenvolvedores e os DBAs.

Requer Sql Server 2008 R2 e Visual Studio 2010 SP1.

Como funciona?

No Visual Studio, há um template de projeto chamado “Data-Tier Application”. Este template organiza em pastas todos os scripts de criação e alteração na base de dados. Tudo escrito em T-SQL, ou seja, uma linguagem bastante natural para quem “desenha” a estrutura de dados.

Dentre os recursos interessantes estão uma checagem de sintaxe, deploy diretamente para uma base de dados e número de versão.

Ao compilar o projeto, o Visual Studio irá gerar um pacote (.dacpac) que pode ser “instalado” e gerenciado no Sql Server.

O .dacpac é como se fosse um instalador (.msi) de banco de dados, onde ele verifica se já existe o pacote instalado e se não existir o cria. Caso já exista, ele atualiza para a versão que se está instalando. Ou seja, o processo é como se estivéssemos instalando ou atualizando um aplicativo no Windows. Show!

Figura 1 – Template de Data-Tier no Visual Studio

Figura 2 – Data-Tier no Sql Server 2008 R2

Opinião

Havia gostado do Data-Tier Application mas o descartei por um simples motivo, o processo de atualização sobre as tabelas que sofreram alterações.

O mecanismo de atualização (in-place upgrade) basicamente funciona da seguinte forma:

  1. A tabela a ser alterada é renomeada para um nome temporário

Este já foi um aspecto que não gostei, pois ao aplicar uma alteração em uma tabela por mais simples que seja, todo o conteúdo se torna indisponível durante o período de atualização.

  1. Uma tabela é criada com a estrutura nova (atualizada)
  2. Os dados da tabela renomeada (velha) são copiados para a nova tabela (nova)

Eis o ponto que definitivamente não gostei. Se eu adicionar um campo, por mais simples que seja, todo o conteúdo da tabela será copiado da tabela renomeada para a nova tabela. Multiplica isso pela quantidade de tabelas que você tem no sistema e que possivelmente terão sofrido alguma alteração. Trágico, não?

Esperava que o mecanismo pudesse ser um pouco mais inteligente do que isso, pelo menos para alterações simples como um aumento no tamanho de um campo nvarchar ou mesmo a adição de um campo passível de ser nulo.

Tirando este aspecto de mover dados ao atualizar uma tabela, a opção de Data-Tier é muito boa, pois atenderia minhas necessidades de segurança e facilidade. Mas por enquanto descartei esta opção.

Code First Migrations

O que é?

Migrations também é uma solução que permite você evoluir a estrutura do banco de dados junto com a evolução do seu modelo de dados (entidades/classes). Dentre as soluções que existem para gerenciar a estrutura de dados a maioria não está integrada ao EF Code First.

Com o Migrations, o conjunto de alterações a serem feitas no banco de dados são expressas na forma de código-fonte C# ou VB.NET, ou seja, não em T-SQL.

Assim como o Data-Tier, o Migrations também é um “instalador” e atualizador de base de dados.

O Migrations está na versão Beta 1 e é disponibilizado junto com o Entity Framework 4.2 através do NuGet.

Como funciona?

No Entity Framework Code First definimos nosso modelo de domínio (entidades/classes) na forma de código-fonte, ou seja, sem usar o modelo visual (.edmx). Definido o modelo, disponibilizamos estas entidades através de um objeto de contexto.

O Migrations trabalha sobre este objeto de contexto.

Ao acionarmos a funcionalidade “add-migration” no Visual Studio, ele analisa o contexto de entidades para identificar quais tabelas são necessárias para armazenar os dados dessas entidades e então gera código-fonte que irá construir ou atualizar uma determinada base de dados.

O código gerado é armazenado em um arquivo no projeto do Visual Studio ordenado por uma linha do tempo (timestamp). Este código tem toda a lógica necessária de levar uma base de dados de um estado zerado para um estado X, ou seja, criar as tabelas definidas no modelo de entidades.

Após gerado o arquivo de migração, basta acionar um outro comando (update-database) para aplicar a migração em uma base de dados.

Na sequencia, ao realizar uma alteração no modelo, basta acionar o comando “add-migration” novamente. Isto irá gerar uma segunda classe de migração refletindo as alterações realizadas no modelo. Por fim, acionamos o “update-database” para aplicar elas na base de dados.

Ao aplicar o “update-database”, o Migrations avalia a base de dados e aplica todas as migrações necessárias para levar a base para o estado mais atual.

Além da atualização normal (upgrade), também é possível fazer o inverso, ou seja, desfazer uma atualização (downgrade).  Isto é possível pois o Migrations gera código com as alterações de atualização como também para desfazer elas.

Muito show, rápido e prático no dia a dia!

Figura 3 – Arquivo gerado pelo Migrations

Figura 4 – Tabela de controle na base de dados

Opinião

No projeto atual já estou utilizando Entity Framework Code First, então avaliar a opção Migrations foi algo natural. Por fim, gostei bastante dessa solução e acabei adotando ela no projeto que estou trabalhando.

Em um primeiro momento parece um pouco estranho definir o banco de dados na forma de código-fonte, mas logo se acostuma e fica bastante rápido e prático. Até porque, quase todo o código é gerado de forma automática e ainda permite adicionar comandos no meio das etapas de migração para ajustes finos.

Uma das vantagens do Migrations sobre o Data-Tier é a questão de aplicar alterações de forma mais inteligente, não sendo necessário mover dados de uma tabela inteira para fazer atualizações nela, além do domínio que temos sobre a ordem e ações de migração. Ou seja, irá aplicar um ALTER TABLE ao invés de recria-la.

Recomendo, mas use com moderação pois ainda está em versão Beta!

Referências

    1. Data-tier Applications in Sql Server 2008 R2: http://download.microsoft.com/download/D/B/D/DBDE7972-1EB9-470A-BA18-58849DB3EB3B/Data-tierAppsInSQLServer2008R2.docx
    2. Developing Data-tier Applications using Visual Studio 2010: http://channel9.msdn.com/Blogs/elisaj/Developing-Data-tier-Applications-using-Visual-Studio-2010
    3. A First Look at Data-Tier Applications 2.0: http://sqlskills.com/BLOGS/BOBB/category/Data-Tier-Applications-(DAC).aspx
    4. Conceitos e ciclo de vida de DAC: http://msdn.microsoft.com/pt-br/library/windowsazure/hh324978.aspx
    5. Code First Migrations: Beta 1 ‘No-Magic’ Walkthrough: http://blogs.msdn.com/b/adonet/archive/2011/11/29/code-first-migrations-beta-1-no-magic-walkthrough.aspx
    6. Code First Migrations: Beta 1 ‘With-Magic’ Walkthrough (Automatic Migrations): http://blogs.msdn.com/b/adonet/archive/2011/11/29/code-first-migrations-beta-1-with-magic-walkthrough-automatic-migrations.aspx

Em próximos artigos devo detalhar mais passo a passo sobre como usar cada uma dessas abordagens. Enquanto isso, não deixe de dar a sua contribuição de como você gerencia a estrutura de banco de dados ao longo de toda a vida de desenvolvimento de um aplicativo.

Até o próximo.

Rafael Leonhardt