Aplicando migrações
Depois que as migrações forem adicionadas, elas precisarão ser implantadas e aplicadas aos bancos de dados. Existem várias estratégias para fazer isso, sendo algumas mais apropriadas para ambientes de produção e outras para o ciclo de vida de desenvolvimento.
Observação
Seja qual for sua estratégia de implantação, sempre inspecione as migrações geradas e teste-as antes de aplicar a um banco de dados de produção. Uma migração pode soltar uma coluna quando a intenção era renomeá-la ou pode falhar por vários motivos quando aplicada a um banco de dados.
Scripts de SQL
A maneira recomendada de implantar migrações para um banco de dados de produção é gerando scripts SQL. As vantagens desta estratégia incluem o seguinte:
- Os scripts SQL podem ser revisados quanto à precisão; Isso é importante, pois aplicar alterações de esquema a bancos de dados de produção é uma operação potencialmente perigosa que pode envolver perda de dados.
- Em alguns casos, os scripts podem ser ajustados para atender às necessidades específicas de um banco de dados de produção.
- Os scripts SQL podem ser usados em conjunto com uma tecnologia de implantação e podem até mesmo ser gerados como parte do seu processo de CI.
- Os scripts SQL podem ser fornecidos a um DBA e podem ser gerenciados e arquivados separadamente.
- da CLI do .NET Core
- Visual Studio
Utilização Básica
O seguinte gera um script SQL de um banco de dados em branco para a migração mais recente:
dotnet ef migrations script
De... a... (para implícito)
O seguinte gera um script SQL da migração dada para a migração mais recente.
dotnet ef migrations script AddNewTables
Com De e Para
O que se segue gera um script de SQL da migração especificada de from
para a migração especificada de to
.
dotnet ef migrations script AddNewTables AddAuditTable
Você pode usar um from
mais recente do que o to
para gerar um script de reversão.
Advertência
Por favor, tome nota de possíveis cenários de perda de dados.
A geração de scripts aceita os dois argumentos a seguir para indicar qual intervalo de migrações deve ser gerado:
- O da migração deve ser a última migração aplicada ao banco de dados antes de executar o script. Se nenhuma migração tiver sido aplicada, especifique
0
(este é o padrão). - O para migração é a última migração que será aplicada ao banco de dados após a execução do script. Por padrão, é utilizada a última migração no seu projeto.
Scripts SQL idempotentes
Os scripts SQL gerados acima só podem ser aplicados para alterar seu esquema de uma migração para outra; É sua responsabilidade aplicar o script adequadamente e somente aos bancos de dados no estado de migração correto. O EF Core também suporta a geração de scripts idempotentes , que verificam internamente quais migrações já foram aplicadas (por meio da tabela de histórico de migrações) e aplicam apenas as ausentes. Isso é útil se você não souber exatamente qual foi a última migração aplicada ao banco de dados ou se estiver implantando em vários bancos de dados que podem estar cada um em uma migração diferente.
O seguinte gera migrações idempotentes:
- da CLI do .NET Core
- Visual Studio
dotnet ef migrations script --idempotent
Ferramentas de linha de comando
As ferramentas de linha de comando do EF podem ser usadas para aplicar migrações a um banco de dados. Embora produtiva para o desenvolvimento local e teste de migrações, essa abordagem não é ideal para gerenciar bancos de dados de produção:
- Os comandos SQL são aplicados diretamente pela ferramenta, sem dar ao desenvolvedor a chance de inspecioná-los ou modificá-los. Isso pode ser perigoso em um ambiente de produção.
- O SDK do .NET e a ferramenta EF devem ser instalados em servidores de produção e requerem o código-fonte do projeto.
- da CLI do .NET Core
- Visual Studio
O seguinte atualiza seu banco de dados para a migração mais recente:
dotnet ef database update
O seguinte atualiza seu banco de dados para uma determinada migração:
dotnet ef database update AddNewTables
Observe que isso também pode ser usado para reverter para uma migração anterior.
Advertência
Por favor, tome nota de possíveis cenários de perda de dados.
Para obter mais informações sobre como aplicar migrações através das ferramentas de linha de comandos, consulte a referência das ferramentas do EF Core .
Pacotes
Os pacotes de migração são executáveis de arquivo único que podem ser usados para aplicar migrações a um banco de dados. Eles abordam algumas das deficiências do script SQL e das ferramentas de linha de comando:
- A execução de scripts SQL requer ferramentas adicionais.
- O manuseio de transações e o comportamento de continuação em caso de erro dessas ferramentas são inconsistentes e, às vezes, inesperados. Isso pode deixar seu banco de dados em um estado indefinido se ocorrer uma falha ao aplicar migrações.
- Os pacotes podem ser gerados como parte do seu processo de CI e facilmente executados posteriormente como parte do seu processo de implantação.
- Os pacotes podem ser executados sem instalar o .NET SDK ou o EF Tool (ou mesmo o .NET Runtime, quando independente) e não exigem o código-fonte do projeto.
- da CLI do .NET Core
- Visual Studio
O seguinte gera um pacote:
dotnet ef migrations bundle
O seguinte gera um pacote autônomo para Linux:
dotnet ef migrations bundle --self-contained -r linux-x64
Para obter mais informações sobre como criar conjuntos, consulte a referência das ferramentas do EF Core .
efbundle
O executável resultante é nomeado efbundle
por padrão. Ele pode ser usado para atualizar o banco de dados para a migração mais recente. É equivalente a executar dotnet ef database update
ou Update-Database
.
Argumentos:
Argumento | Descrição |
---|---|
<MIGRATION> |
A migração alvo. Se '0', todas as migrações serão revertidas. Define-se como padrão a última migração. |
Opções:
Opção | Curto | Descrição |
---|---|---|
--connection <CONNECTION> |
A cadeia de conexão com o banco de dados. Assume o valor predefinido especificado em AddDbContext ou OnConfiguring. | |
--verbose |
-v |
Mostrar saída detalhada. |
--no-color |
Não colorir a saída. | |
--prefix-output |
Prefixar a saída com o nível. |
O exemplo a seguir aplica migrações a uma instância local do SQL Server usando o nome de usuário e as credenciais especificados:
.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password={;'$Credential;'here'}'
Advertência
Não se esqueça de copiar appsettings.json junto com o seu pacote. O pacote depende da presença de appsettings.json no diretório de execução.
Exemplo de pacote de migração
Um pacote precisa de migrações para ser incluído. Eles são criados usando o dotnet ef migrations add
, conforme descrito em Crie a sua primeira migração. Depois de ter migrações prontas para implantação, crie um pacote usando o dotnet ef migrations bundle
. Por exemplo:
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>
A saída é um executável adequado para o seu sistema operacional de destino. No meu caso, este é o Windows x64, então eu recebo um efbundle.exe
deixado na minha pasta local. A execução deste executável aplica as migrações contidas nele:
PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903083845_MyMigration'.
Done.
PS C:\local\AllTogetherNow\SixOh>
Tal como acontece com dotnet ef database update
ou Update-Database
, as migrações são aplicadas ao banco de dados somente se ainda não tiverem sido aplicadas. Por exemplo, executar o mesmo pacote novamente não faz nada, já que não há novas migrações a serem aplicadas:
PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
No migrations were applied. The database is already up to date.
Done.
PS C:\local\AllTogetherNow\SixOh>
No entanto, se forem feitas alterações no modelo e mais migrações forem geradas com dotnet ef migrations add
, elas poderão ser agrupadas em um novo executável pronto para ser aplicado. Por exemplo:
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add SecondMigration
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add Number3
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle --force
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>
Dica
A opção --force
pode ser usada para substituir o pacote existente por um novo.
A execução deste novo pacote aplica estas duas novas migrações ao banco de dados:
PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>
Por padrão, o pacote usa a cadeia de conexão de banco de dados da configuração do seu aplicativo. No entanto, um banco de dados diferente pode ser migrado passando a cadeia de conexão na linha de comando. Por exemplo:
PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe --connection "Data Source=(LocalDb)\MSSQLLocalDB;Database=SixOhProduction"
Applying migration '20210903083845_MyMigration'.
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>
Observação
Desta vez, as três migrações foram aplicadas, uma vez que nenhuma delas ainda havia sido aplicada ao banco de dados de produção.
Aplicar migrações em tempo de execução
É possível que o próprio aplicativo aplique migrações programaticamente, normalmente durante a inicialização. Embora produtiva para o desenvolvimento local e teste de migrações, essa abordagem é inadequada para gerenciar bancos de dados de produção, pelos seguintes motivos:
- Para versões do EF anteriores a 9, se várias instâncias do seu aplicativo estiverem em execução, ambos os aplicativos poderão tentar aplicar a migração simultaneamente e falhar (ou pior, causar corrupção de dados).
- Da mesma forma, se um aplicativo estiver acessando o banco de dados enquanto outro aplicativo o migra, isso pode causar problemas graves.
- O aplicativo deve ter acesso elevado para modificar o esquema do banco de dados. Geralmente, é uma boa prática limitar as permissões do banco de dados do aplicativo em produção.
- É importante poder reverter uma migração aplicada em caso de problema. As outras estratégias fornecem isso facilmente e fora da caixa.
- Os comandos SQL são aplicados diretamente pelo programa, sem dar ao desenvolvedor a chance de inspecioná-los ou modificá-los. Isso pode ser perigoso em um ambiente de produção.
Para aplicar migrações programaticamente, chame context.Database.MigrateAsync()
. Por exemplo, um aplicativo ASP.NET típico pode fazer o seguinte:
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await db.Database.MigrateAsync();
}
host.Run();
}
Observe que MigrateAsync()
se baseia no serviço IMigrator
, que pode ser usado para cenários mais avançados. Use myDbContext.GetInfrastructure().GetService<IMigrator>()
para acessá-lo.
Advertência
- Considere cuidadosamente antes de usar essa abordagem na produção. A experiência demonstrou que a simplicidade desta estratégia de implantação é superada pelos problemas que cria. Em vez disso, considere gerar scripts SQL a partir de migrações.
- Não ligue para
EnsureCreatedAsync()
antes deMigrateAsync()
.EnsureCreatedAsync()
ignora Migrações para criar o esquema, o que faz com queMigrateAsync()
falhe.