Compartilhar via


Migrações Code First com um banco de dados existente

Observação

EF4.3 Somente em diante – os recursos, APIs etc. discutidos nesta página foram introduzidos no Entity Framework 4.1. Se você estiver usando uma versão anterior, algumas ou todas as informações não se aplicarão.

Este artigo aborda o uso de Migrações do Code First com um banco de dados existente, um que não foi criado pelo Entity Framework.

Observação

Este artigo pressupõe que você saiba como usar as Migrações do Code First em cenários básicos. Se não, será necessário ler Code First Migrations antes de continuar.

Etapa 1: Criar um modelo

Sua primeira etapa será criar um modelo Code First que aponte para o banco de dados existente. O tópico Code First to an Existing Database fornece diretrizes detalhadas sobre como fazer isso.

Observação

É importante seguir o restante das etapas deste tópico antes de fazer qualquer alteração no modelo que exija alterações no esquema de banco de dados. As etapas a seguir exigem que o modelo esteja em sincronia com o esquema de banco de dados.

Etapa 2: Habilitar migrações

A próxima etapa é habilitar as migrações. Você pode fazer isso executando o comando Habilitar Migrações no Console do Gerenciador de Pacotes .

Esse comando criará uma pasta em sua solução chamada Migrações e colocará uma única classe dentro dela chamada Configuração. A classe Configuração é onde você configura as migrações para seu aplicativo, você pode saber mais sobre ela no tópico Code First Migrations .

Etapa 3: Adicionar uma migração inicial

Depois que as migrações tiverem sido criadas e aplicadas ao banco de dados local, talvez você também queira aplicar essas alterações a outros bancos de dados. Por exemplo, seu banco de dados local pode ser um banco de dados de teste e, em última análise, você pode querer aplicar também as alterações a um banco de dados de produção e/ou a outros desenvolvedores que testam bancos de dados. Há duas opções para esta etapa e a que você deve escolher depende se o esquema de outros bancos de dados está ou não vazio ou corresponde atualmente ao esquema do banco de dados local.

  • Opção Um: use o esquema existente como ponto de partida. Você deve usar essa abordagem quando outros bancos de dados aos quais as migrações serão aplicadas no futuro terão o mesmo esquema que o banco de dados local atualmente. Por exemplo, você poderá usá-lo se o banco de dados de teste local corresponder atualmente à v1 do banco de dados de produção e, posteriormente, aplicar essas migrações para atualizar o banco de dados de produção para v2.
  • Opção Dois: usar o banco de dados vazio como ponto de partida. Você deve usar essa abordagem quando outros bancos de dados aos quais as migrações serão aplicadas no futuro estiverem vazios (ou ainda não existirem). Por exemplo, você poderá usá-lo se começar a desenvolver seu aplicativo usando um banco de dados de teste, mas sem usar migrações e, posteriormente, desejar criar um banco de dados de produção do zero.

Opção Um: usar o esquema existente como ponto de partida

O Code First Migrations usa um instantâneo do modelo armazenado na migração mais recente para detectar alterações no modelo (você pode encontrar informações detalhadas sobre isso em Migrações do Code First em Ambientes de Equipe). Como estamos assumindo que os bancos de dados já têm o esquema do modelo atual, geraremos uma migração vazia (no-op) que tenha o modelo atual como uma captura instantânea.

  1. Execute o comando Add-Migration InitialCreate –IgnoreChanges no Console do Gerenciador de Pacotes. Isso cria uma migração vazia com o modelo atual como um snapshot.
  2. Execute o comando Update-Database no Console do Gerenciador de Pacotes. Isso aplicará a migração InitialCreate ao banco de dados. Como a migração real não contém nenhuma alteração, ela simplesmente adicionará uma linha à tabela __MigrationsHistory indicando que essa migração já foi aplicada.

Opção Dois: usar o banco de dados vazio como ponto de partida

Nesse cenário, precisamos que as Migrações possam criar o banco de dados inteiro do zero, incluindo as tabelas que já se encontram em nosso banco de dados local. Vamos gerar uma migração InitialCreate que inclui lógica para criar o esquema existente. Em seguida, faremos com que nosso banco de dados existente pareça que essa migração já foi aplicada.

  1. Execute o comando Add-Migration InitialCreate no Console do Gerenciador de Pacotes. Isso cria uma migração para criar o esquema existente.
  2. Comente todo o código no método Up da migração recém-criada. Isso nos permitirá 'aplicar' a migração para o banco de dados local sem tentar recriar todas as tabelas etc. que já existem.
  3. Execute o comando Update-Database no Console do Gerenciador de Pacotes. Isso aplicará a migração InitialCreate ao banco de dados. Como a migração real não contém alterações (porque as comentamos temporariamente), ela simplesmente adicionará uma linha à tabela __MigrationsHistory indicando que essa migração já foi aplicada.
  4. Cancele o comentário do código no método Up. Isso significa que, quando essa migração é aplicada a bancos de dados futuros, o esquema que já existia no banco de dados local será criado por migrações.

Coisas que devem ser observadas

Há algumas coisas que você precisa estar ciente ao usar migrações em um banco de dados existente.

Nomes padrão/calculados podem não corresponder ao esquema existente

As migrações especificam explicitamente nomes para colunas e tabelas quando ela estrutura uma migração. No entanto, há outros objetos de banco de dados para os quais as Migrações calculam um nome padrão ao aplicar as migrações. Isso inclui índices e restrições de chave estrangeira. Ao direcionar um esquema existente, esses nomes calculados podem não corresponder ao que realmente existe em seu banco de dados.

Aqui estão alguns exemplos de quando você precisa estar ciente disso:

Se você usou a "Opção Um: usar o esquema existente como ponto de partida" da Etapa 3:

  • Se alterações futuras no seu modelo exigirem a alteração ou remoção de um dos objetos de banco de dados cujos nomes são diferentes, você precisará modificar a migração gerada automaticamente para especificar o nome correto. As APIs de Migrações têm um parâmetro de Nome opcional que permite que você faça isso. Por exemplo, seu esquema existente pode ter uma tabela Post com uma coluna de chave estrangeira BlogId que tem um índice chamado IndexFk_BlogId. No entanto, por padrão, as migrações esperariam que esse índice fosse nomeado IX_BlogId. Se você fizer uma alteração no modelo que resulte na remoção desse índice, será necessário modificar a chamada scaffolded DropIndex para especificar o nome IndexFk_BlogId.

Se você usou 'Opção Dois: Usar banco de dados vazio como ponto de partida' da Etapa 3:

  • A tentativa de executar o método Down da migração inicial (ou seja, reverter para um banco de dados vazio) no banco de dados local pode falhar porque as Migrações tentarão remover índices e restrições de chave estrangeira usando os nomes incorretos. Isso só afetará seu banco de dados local, pois outros bancos de dados serão criados do zero usando o método Up da migração inicial. Se você quiser fazer downgrade do banco de dados local existente para um estado vazio, é mais fácil fazer isso manualmente, descartando o banco de dados ou descartando todas as tabelas. Após esse downgrade inicial, todos os objetos de banco de dados serão recriados com os nomes padrão, portanto, esse problema não se apresentará novamente.
  • Se alterações futuras em seu modelo exigirem a alteração ou a remoção de um dos objetos de banco de dados nomeados de forma diferente, isso não funcionará em relação ao banco de dados local existente, pois os nomes não corresponderão aos padrões. No entanto, ele funcionará com bancos de dados que foram criados "do zero", pois eles terão usado os nomes padrão escolhidos pelo Migrations. Você pode fazer essas alterações manualmente em seu banco de dados local existente ou considerar fazer com que as Migrações recriem seu banco de dados do zero, como em outros computadores.
  • Os bancos de dados criados usando o método Up da migração inicial podem ser ligeiramente diferentes do banco de dados local, pois os nomes padrão calculados para índices e restrições de chave estrangeira serão usados. Você também pode acabar com índices extras, pois as Migrações criarão índices em colunas de chave estrangeira por padrão. Isso pode não ter sido o caso no banco de dados local original.

Nem todos os objetos de banco de dados são representados no modelo

Objetos de banco de dados que não fazem parte do modelo não serão tratados pelas Migrações. Isso pode incluir exibições, procedimentos armazenados, permissões, tabelas que não fazem parte do modelo, índices adicionais etc.

Aqui estão alguns exemplos de quando você precisa estar ciente disso:

  • Independentemente da opção que você escolheu na "Etapa 3", se alterações futuras no modelo exigirem alterar ou descartar esses objetos adicionais, as migrações não saberão fazer essas alterações. Por exemplo, se você eliminar uma coluna que tenha um índice adicional, o Migrations não saberá remover o índice. Você precisará adicionar isso manualmente à migração gerada automaticamente.
  • Se você usou 'Opção Dois: Usar banco de dados vazio como ponto de partida', esses objetos adicionais não serão criados pelo método Up da migração inicial. Você pode modificar os métodos Up e Down para cuidar desses objetos adicionais, se desejar. Para objetos que não têm suporte nativo na API de Migrações , como exibições, você pode usar o método Sql para executar o SQL bruto para criá-los/soltá-los.