Como habilito migrações EF para vários contextos para separar bancos de dados?

122

Como habilito as migrações do Entity Framework 5 (versão 5.0.0) para vários contextos de banco de dados no mesmo projeto, em que cada contexto corresponde ao seu próprio banco de dados? Quando executo Enable-Migrationsno console PM (Visual Studio 2012), ocorre um erro devido a vários contextos:

PM> Enable-Migrations
More than one context type was found in the assembly 'DatabaseService'.
To enable migrations for DatabaseService.Models.Product1DbContext, use Enable-Migrations -ContextTypeName DatabaseService.Models.Product1DbContext.
To enable migrations for DatabaseService.Models.Product2DbContext, use Enable-Migrations -ContextTypeName DatabaseService.Models.Product2DbContext.

Se eu executar, Enable-Migrations -ContextTypeName DatabaseService.Models.Product1DbContextnão tenho permissão para executar Enable-Migrations -ContextTypeName DatabaseService.Models.Product2DbContextporque já existe uma migração:Migrations have already been enabled in project 'DatabaseService'. To overwrite the existing migrations configuration, use the -Force parameter.

aknuds1
fonte

Respostas:

126

A segunda chamada para Enable-Migrations está falhando porque o arquivo Configuration.cs já existe. Se você renomear essa classe e arquivo, poderá executar a 2ª Enable-Migrations, que criará outro Configuration.cs.

Você precisará especificar qual configuração deseja usar ao atualizar os bancos de dados.

Update-Database -ConfigurationTypeName MyRenamedConfiguration
ckal
fonte
1
O que é "MyRenamedConfiguration"?
precisa
1
"MyRenamedConfiguration" é apenas um texto reservado como exemplo. Você poderia ter renomeado seu Configuration.cs original para qualquer coisa (por exemplo, FooBar, em seguida, execute Update-Database -ConfigurationTypeName FooBar).
ckal
3
formato abreviado: Update-Database -conf MyRenamedConfiguration
Peter Kerr
100

Além do que o @ckal sugeriu, é essencial atribuir a cada Configuration.cs renomeado seu próprio espaço para nome. Caso contrário, a EF tentará aplicar migrações ao contexto errado.

Aqui estão as etapas específicas que funcionam bem para mim.

Se as migrações estiverem erradas e você desejar criar uma nova "linha de base":

  1. Exclua todos os arquivos .cs existentes na pasta Migrações
  2. No SSMS, exclua a tabela do sistema __MigrationHistory.

Criando a migração inicial:

  1. No Console do Gerenciador de Pacotes:

    Enable-Migrations -EnableAutomaticMigrations -ContextTypeName
    NamespaceOfContext.ContextA -ProjectName ProjectContextIsInIfNotMainOne
    -StartupProjectName NameOfMainProject  -ConnectionStringName ContextA
  2. No Gerenciador de Soluções: Renomeie Migrations.Configuration.cs para Migrations.ConfigurationA.cs. Isso deve renomear automaticamente o construtor se estiver usando o Visual Studio. Certifique-se de que sim. Editar ConfigurationA.cs: altere o namespace para NamespaceOfContext.Migrations.MigrationsA

  3. Enable-Migrations -EnableAutomaticMigrations -ContextTypeName
    NamespaceOfContext.ContextB -ProjectName ProjectContextIsInIfNotMainOne
    -StartupProjectName NameOfMainProject  -ConnectionStringName ContextB
  4. No Solution Explorer: Renomeie Migrations.Configuration.cs para Migrations.ConfigurationB.cs. Novamente, verifique se o construtor também foi renomeado adequadamente. Editar ConfigurationB.cs: altere o espaço para nome para NamespaceOfContext.Migrations.MigrationsB

  5. add-migration InitialBSchema -IgnoreChanges -ConfigurationTypeName
    ConfigurationB -ProjectName ProjectContextIsInIfNotMainOne
    -StartupProjectName NameOfMainProject  -ConnectionStringName ContextB 
  6. Update-Database -ConfigurationTypeName ConfigurationB -ProjectName
    ProjectContextIsInIfNotMainOne -StartupProjectName NameOfMainProject
    -ConnectionStringName ContextB
  7. add-migration InitialSurveySchema -IgnoreChanges -ConfigurationTypeName
    ConfigurationA -ProjectName ProjectContextIsInIfNotMainOne -StartupProjectName
    NameOfMainProject  -ConnectionStringName ContextA 
  8. Update-Database -ConfigurationTypeName ConfigurationA -ProjectName
    ProjectContextIsInIfNotMainOne -StartupProjectName NameOfMainProject
    -ConnectionStringName ContextA

Etapas para criar scripts de migração no Console do Gerenciador de Pacotes:

  1. Comando de execução

    Add-Migration MYMIGRATION -ConfigurationTypeName ConfigurationA -ProjectName
    ProjectContextIsInIfNotMainOne -StartupProjectName NameOfMainProject
    -ConnectionStringName ContextA

    ou -

    Add-Migration MYMIGRATION -ConfigurationTypeName ConfigurationB -ProjectName
    ProjectContextIsInIfNotMainOne -StartupProjectName NameOfMainProject
    -ConnectionStringName ContextB

    Não há problema em executar novamente este comando até que as alterações sejam aplicadas ao banco de dados.

  2. Execute os scripts no banco de dados local desejado ou execute o Update-Database sem -Script para aplicar localmente:

    Update-Database -ConfigurationTypeName ConfigurationA -ProjectName
    ProjectContextIsInIfNotMainOne -StartupProjectName NameOfMainProject
    -ConnectionStringName ContextA

    ou -

    Update-Database -ConfigurationTypeName ConfigurationB -ProjectName
    ProjectContextIsInIfNotMainOne -StartupProjectName NameOfMainProject
    -ConnectionStringName ContextB
Eric J.
fonte
# 4 change: Edit ConfigurationA.cs -> Edit ConfigurationB.cs
Brian Rizo
1
@ Biran: Obrigado por perceber isso. Eu editei a resposta. Observe que você também pode editar as respostas. Como você ainda não possui reputação em 2000, suas respostas são inseridas em uma fila de revisão, mas essa fila geralmente é trabalhada rapidamente, portanto sua edição provavelmente teria sido aprovada em alguns minutos.
22714 Eric Eric
5
OBRIGADO! Era isso que eu estava perdendo (os namespaces).
William M. Rawls
Isso pode ajudar porque não ficou claro para mim como renomear as etapas 2 e 4 inicialmente: Quando você renomeia o arquivo Configuration.cs para ConfigurationA.cs ou ConfigurationB.cs, a renomeação também deve resultar na classe e seu construtor sendo renomeado para ConfigurationA ou ConfigurationB também. A falha em renomear a classe causará uma mensagem de erro quando você executar o comando add-migration - "O tipo de configuração de migração 'ConfigurationA' não foi encontrado no assembly '...'" - e sim, as palavras estavam incorretas, como que nas mensagens de erro que recebi no VS2013 - LOL
Greg Barth
3
isso me ajudou! instruções completas com todas as opções e pedidos. me salvou horas
elcool
81

Acabei de encontrar o mesmo problema e usei a seguinte solução (todas do Package Manager Console)

PM> Enable-Migrations -MigrationsDirectory "Migrations\ContextA" -ContextTypeName MyProject.Models.ContextA
PM> Enable-Migrations -MigrationsDirectory "Migrations\ContextB" -ContextTypeName MyProject.Models.ContextB

Isso criará 2 pastas separadas na pasta Migrações. Cada um conterá o Configuration.csarquivo gerado . Infelizmente, você ainda precisa renomear esses Configuration.csarquivos, caso contrário, haverá reclamações sobre a existência de dois deles. Renomeei meus arquivos para ConfigA.cseConfigB.cs

EDIT : (cortesia de Kevin McPheat) Lembre-se de renomear os arquivos Configuration.cs, renomeie também os nomes de classe e os construtores / EDIT

Com essa estrutura você pode simplesmente fazer

PM> Add-Migration -ConfigurationTypeName ConfigA
PM> Add-Migration -ConfigurationTypeName ConfigB

O que criará os arquivos de código para a migração dentro da pasta ao lado dos arquivos de configuração (é bom manter esses arquivos juntos)

PM> Update-Database -ConfigurationTypeName ConfigA
PM> Update-Database -ConfigurationTypeName ConfigB

E por último, mas não menos importante, esses dois comandos aplicarão as migrações corretas aos bancos de dados correspondentes.

EDIT 08 Fev 2016: Fiz um pequeno teste com o EF7 versão 7.0.0-rc1-16348

Não foi possível obter a opção -o | --outputDir para funcionar. Continuou dandoMicrosoft.Dnx.Runtime.Common.Commandline.CommandParsingException: Unrecognized command or argument

No entanto, parece que na primeira vez em que uma migração é adicionada, ela é adicionada à pasta Migrações e uma migração subsequente para outro contexto é automaticamente colocada em uma subpasta de migrações.

Os nomes originais ContextAparecem violar algumas convenções de nomenclatura, então agora eu uso o ContextAContexte ContextBContext. Usando esses nomes, você pode usar os seguintes comandos: (observe que meu dnx ainda funciona no console do gerenciador de pacotes e não gosto de abrir uma janela CMD separada para fazer migrações)

PM> dnx ef migrations add Initial -c "ContextAContext"
PM> dnx ef migrations add Initial -c "ContextBContext"

Isso criará um instantâneo do modelo e uma migração inicial na Migrationspasta para ContextAContext. Ele criará uma pasta chamada ContextBcontendo esses arquivos paraContextBContext

Adicionei manualmente uma ContextApasta e movi os arquivos de migração ContextAContextpara essa pasta. Renomeei o nome do namespace dentro desses arquivos (arquivo de instantâneo, migração inicial e observe que há um terceiro arquivo no arquivo de migração inicial ... designer.cs). Eu tive que adicionar .ContextAao espaço para nome e a partir daí a estrutura lida com ele automaticamente novamente.

O uso dos seguintes comandos criaria uma nova migração para cada contexto

PM>  dnx ef migrations add Update1 -c "ContextAContext"
PM>  dnx ef migrations add Update1 -c "ContextBContext"

e os arquivos gerados são colocados nas pastas corretas.

bart s
fonte
5
a melhor solução, simples e mantemos uma pasta limpa.
Malick #
2
Essa era a resposta que eu precisava. O espaço para nome adicionado via -MigrationsDirectory foi a resposta! Obrigado.
Crob 18/05/19
1
Solução agradável e limpa. Obrigado.
Stefan Cebulak
4
1,5 ano depois, estou feliz por poder usar meu próprio post para configurar um novo projeto.
Bart s
1
Observe que quando você o executar, você add-migrationserá solicitado Name. Isso me assustou um pouco, já que eu já estava fornecendo ConfigurationTypeNamee fiquei um pouco irritado quando acabou de dizer Name:. Mas é claro que o Nome que ele quer é a descrição 'legível por humanos' da mudança - por exemplo. AddedProductsou IncreaseLengthOfNameFields. Na pasta Migrações, você obtém isso como parte do nome da classe, portanto é fácil ver o que é o quê. Então, na verdade, Nameé como um comentário de check-in.
Simon_Weaver
7

Caso você já tenha uma "Configuração" com muitas migrações e queira mantê-la como está, sempre poderá criar uma nova classe "Configuração", com outro nome, como

class MyNewContextConfiguration : DbMigrationsConfiguration<MyNewDbContext>
{
   ...
}

então apenas emita o comando

Add-Migration -ConfigurationTypeName MyNewContextConfiguration InitialMigrationName

e a EF acompanhará a migração sem problemas. Finalmente, atualize seu banco de dados; a partir de agora, a EF reclamará se você não informar a ele qual configuração você deseja atualizar:

Update-Database -ConfigurationTypeName MyNewContextConfiguration 

Feito.

Você não precisa lidar com Enable-Migrations, pois ele reclamará que "Configuração" já existe e renomear sua classe de configuração existente trará problemas ao histórico de migração.

Você pode segmentar bancos de dados diferentes, ou o mesmo, todas as configurações compartilharão a tabela __MigrationHistory de maneira agradável.

Guillermo Ruffino
fonte
4

Se houver mais bancos de dados, use os seguintes códigos no PowerShell

Add-Migration Starter -context EnrollmentAppContext 
  • 'Starter' é o nome da migração

  • 'EnrollmentAppContext' é o nome do meu aplicativo

Você pode abrir o PowerShell no VS fazendo o seguinte: Tools->NuGet Package Manager->Package Manager Console

AHAMED AAQIB
fonte
1
Isso me ajudou. Obrigado! :)
noobprogrammer
3

Para atualizar o tipo de banco de dados a seguir nos códigos do PowerShell ...

Update-Database -context EnrollmentAppContext

* se houver mais de um banco de dados, use apenas esses códigos; caso contrário, não será necessário.

AHAMED AAQIB
fonte
0

Na verdade, o EF 4.7 dá uma dica quando você executa Enable-migrations em múltiplos contextos.

Mais de um tipo de contexto foi encontrado no assembly 'Service.Domain'.

To enable migrations for 'Service.Domain.DatabaseContext.Context1', 
use Enable-Migrations -ContextTypeName Service.Domain.DatabaseContext.Context1.
To enable migrations for 'Service.Domain.DatabaseContext.Context2',
use Enable-Migrations -ContextTypeName Service.Domain.DatabaseContext.Context2.
Davit Mikuchadze
fonte