Minha impressão até o momento foi que a DbContext
pretende representar seu banco de dados e, portanto, se seu aplicativo usa um banco de dados, você deseja apenas um DbContext
.
No entanto, alguns colegas querem dividir as áreas funcionais em DbContext
classes separadas .
Eu acredito que isso vem de um bom lugar - um desejo de manter o código mais limpo - mas parece volátil. Meu intestino está me dizendo que é uma má idéia, mas, infelizmente, meu pressentimento não é uma condição suficiente para uma decisão de design.
Então, eu estou procurando:
A) exemplos concretos de por que isso pode ser uma má idéia;
B) garantias de que tudo isso funcionará perfeitamente.
entity-framework
ef-code-first
entity-framework-4.3
dbcontext
Josh Schultz
fonte
fonte
Respostas:
Você pode ter vários contextos para um único banco de dados. Pode ser útil, por exemplo, se seu banco de dados contiver vários esquemas de banco de dados e você desejar manipular cada um deles como uma área independente separada.
O problema é quando você deseja usar o código primeiro para criar seu banco de dados - apenas um único contexto no seu aplicativo pode fazer isso. O truque para isso é geralmente um contexto adicional contendo todas as suas entidades que é usado apenas para a criação do banco de dados. Seus contextos de aplicativos reais que contêm apenas subconjuntos de suas entidades devem ter o inicializador de banco de dados definido como nulo.
Existem outros problemas que você verá ao usar vários tipos de contexto - por exemplo, tipos de entidade compartilhada e sua passagem de um contexto para outro, etc. Geralmente é possível, ele pode tornar seu design muito mais limpo e separar diferentes áreas funcionais, mas possui suas características. custos com complexidade adicional.
fonte
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
funciona agora.Escrevi esta resposta há cerca de quatro anos e minha opinião não mudou. Mas desde então, houve desenvolvimentos significativos na frente de microsserviços. Adicionei notas específicas sobre microsserviços no final ...
Eu vou pesar contra a idéia, com experiência no mundo real para apoiar meu voto.
Fui levado a um aplicativo grande que tinha cinco contextos para um único banco de dados. No final, acabamos removendo todos os contextos, exceto um - revertendo para um único contexto.
A princípio, a ideia de múltiplos contextos parece uma boa ideia. Podemos separar nosso acesso a dados em domínios e fornecer vários contextos leves e limpos. Parece DDD, certo? Isso simplificaria nosso acesso a dados. Outro argumento é para o desempenho, pois apenas acessamos o contexto que precisamos.
Mas, na prática, à medida que nosso aplicativo crescia, muitas de nossas tabelas compartilhavam relacionamentos entre nossos vários contextos. Por exemplo, as consultas à tabela A no contexto 1 também exigiam a junção da tabela B no contexto 2.
Isso nos deixou com algumas escolhas ruins. Poderíamos duplicar as tabelas nos vários contextos. Nós tentamos isso. Isso criou vários problemas de mapeamento, incluindo uma restrição EF que requer que cada entidade tenha um nome exclusivo. Então, acabamos com entidades nomeadas Person1 e Person2 nos diferentes contextos. Pode-se argumentar que esse projeto foi ruim da nossa parte, mas, apesar dos nossos melhores esforços, é assim que nosso aplicativo realmente cresceu no mundo real.
Também tentamos consultar os dois contextos para obter os dados necessários. Por exemplo, nossa lógica de negócios consultaria metade do que era necessário no contexto 1 e a outra metade no contexto 2. Isso apresentava alguns problemas importantes. Em vez de executar uma consulta em um único contexto, tivemos que realizar várias consultas em diferentes contextos. Isso tem uma penalidade de desempenho real.
No final, a boa notícia é que foi fácil remover os múltiplos contextos. O contexto pretende ser um objeto leve. Portanto, não acho que o desempenho seja um bom argumento para vários contextos. Em quase todos os casos, acredito que um único contexto é mais simples, menos complexo e provavelmente terá um desempenho melhor, e você não precisará implementar várias soluções alternativas para fazê-lo funcionar.
Pensei em uma situação em que múltiplos contextos poderiam ser úteis. Um contexto separado pode ser usado para corrigir um problema físico no banco de dados no qual ele realmente contém mais de um domínio. Idealmente, um contexto seria um para um em um domínio, que seria um para um em um banco de dados. Em outras palavras, se um conjunto de tabelas não estiver relacionado às outras tabelas em um determinado banco de dados, elas provavelmente deverão ser extraídas para um banco de dados separado. Sei que isso nem sempre é prático. Mas se um conjunto de tabelas for tão diferente que você se sinta à vontade para separá-las em um banco de dados separado (mas você optar por não), eu poderia ver o caso de usar um contexto separado, mas apenas porque na verdade existem dois domínios separados.
Em relação aos microsserviços, um único contexto ainda faz sentido. No entanto, para microsserviços, cada serviço teria seu próprio contexto, que inclui apenas as tabelas de banco de dados relevantes para esse serviço. Em outras palavras, se o serviço x acessar as tabelas 1 e 2 e o serviço y acessar as tabelas 3 e 4, cada serviço terá seu próprio contexto exclusivo, que inclui tabelas específicas para esse serviço.
Estou interessado em seus pensamentos.
fonte
Esse tópico apenas surgiu no StackOverflow e, portanto, eu queria oferecer outra garantia "B) de que tudo ficará bem" :)
Estou fazendo exatamente isso por meio do padrão DDD Bounded Context. Eu escrevi sobre isso em meu livro, Programming Entity Framework: DbContext e é o foco de um módulo de 50 minutos em um dos meus cursos sobre Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
fonte
Distinguindo contextos configurando o esquema padrão
No EF6, você pode ter vários contextos, basta especificar o nome do esquema de banco de dados padrão no
OnModelCreating
método da suaDbContext
classe derivada (onde está a configuração da API do Fluent). Isso funcionará no EF6:Este exemplo usará "Customer" como prefixo para suas tabelas de banco de dados (em vez de "dbo"). Mais importante, ele também prefixará a
__MigrationHistory
(s) tabela (s), por exemploCustomer.__MigrationHistory
. Portanto, você pode ter mais de uma__MigrationHistory
tabela em um único banco de dados, uma para cada contexto. Portanto, as alterações feitas em um contexto não interferem no outro.Ao adicionar a migração, especifique o nome completo da sua classe de configuração (derivada de
DbMigrationsConfiguration
) como parâmetro noadd-migration
comando:Uma palavra curta na chave de contexto
De acordo com este artigo do MSDN " Capítulo - Vários modelos direcionados para o mesmo banco de dados ", o EF 6 provavelmente lidaria com a situação mesmo que houvesse apenas uma
MigrationHistory
tabela, porque na tabela há uma coluna ContextKey para distinguir as migrações.No entanto, prefiro ter mais de uma
MigrationHistory
tabela especificando o esquema padrão, como explicado acima.Usando pastas de migração separadas
Nesse cenário, você também pode querer trabalhar com diferentes pastas "Migração" em seu projeto. Você pode configurar sua
DbMigrationsConfiguration
classe derivada de acordo usando aMigrationsDirectory
propriedade:Resumo
Em suma, você pode dizer que tudo está bem separado: contextos, pastas de migração no projeto e tabelas no banco de dados.
Eu escolheria essa solução, se houver grupos de entidades que fazem parte de um tópico maior, mas não estão relacionados (por meio de chaves estrangeiras) entre si.
Se os grupos de entidades não tiverem o que fazer, eu criaria um banco de dados separado para cada uma delas e também as acessaria em projetos diferentes, provavelmente com um único contexto em cada projeto.
fonte
Exemplo simples para obter o abaixo:
Apenas escopo as propriedades no contexto principal: (usado para criar e manter o banco de dados) Nota: Apenas use protected: (A entidade não é exposta aqui)
MonitorContext: exponha uma entidade separada aqui
Modelo de diagnóstico:
Se desejar, você pode marcar todas as entidades como protegidas dentro do ApplicationDbContext principal, crie contextos adicionais conforme necessário para cada separação de esquemas.
Todos eles usam a mesma cadeia de conexão, no entanto, usam conexões separadas; portanto, não cruzam transações e estejam cientes dos problemas de bloqueio. Geralmente o seu projeto de separação, portanto, isso não deve acontecer de qualquer maneira.
fonte
DbSet<x>
definição. Eu faço isso em uma classe parcial que corresponde ao que o EF Designer faz.Lembrete: Se você combinar vários contextos, corte e cole todas as funcionalidades dos seus vários
RealContexts.OnModelCreating()
no seu singleCombinedContext.OnModelCreating()
.Eu perdi tempo procurando por que meus relacionamentos de exclusão em cascata não estavam sendo preservados apenas para descobrir que eu não havia transportado o
modelBuilder.Entity<T>()....WillCascadeOnDelete();
código do meu contexto real para o meu contexto combinado.fonte
OtherContext.OnModelCreating()
do seu contexto combinado?Meu intestino me disse a mesma coisa quando me deparei com este design.
Estou trabalhando em uma base de código onde existem três dbContexts em um banco de dados. 2 dos 3 dbcontexts dependem das informações de 1 dbcontext, porque ele fornece os dados administrativos. Esse design colocou restrições sobre como você pode consultar seus dados. Corri para esse problema em que você não pode ingressar nos dbcontexts. Em vez disso, o que você precisa fazer é consultar os dois dbcontexts separados e, em seguida, fazer uma junção na memória ou iterar através de ambos para obter a combinação dos dois como um conjunto de resultados. O problema é que, em vez de consultar um conjunto de resultados específico, você está carregando todos os seus registros na memória e fazendo uma junção nos dois conjuntos de resultados na memória. Pode realmente atrasar as coisas.
Eu faria a pergunta "só porque você pode, deveria? "
Consulte este artigo para o problema que me deparei relacionado a este design. A expressão LINQ especificada contém referências a consultas associadas a diferentes contextos
fonte
Inspirado no [artigo DDD MSDN Mag de 2013 de JulieLerman] [1]
fonte
No código primeiro, você pode ter vários DBContext e apenas um banco de dados. Você apenas precisa especificar a cadeia de conexão no construtor.
fonte
Mais um pouco de "sabedoria". Eu tenho um banco de dados voltado para ambos, a Internet e um aplicativo interno. Eu tenho um contexto para cada rosto. Isso me ajuda a manter uma segregação segura e disciplinada.
fonte
Quero compartilhar um caso em que acho que a possibilidade de ter vários DBContexts no mesmo banco de dados faz sentido.
Eu tenho uma solução com dois banco de dados. Um é para dados do domínio, exceto informações do usuário. O outro é apenas para informações do usuário. Esta divisão é impulsionada principalmente pelo Regulamento Geral de Proteção de Dados da UE . Por ter dois bancos de dados, posso mover livremente os dados do domínio (por exemplo, do Azure para o meu ambiente de desenvolvimento), desde que os dados do usuário permaneçam em um local seguro.
Agora, para o banco de dados do usuário, implementei dois esquemas através do EF. Um é o padrão fornecido pela estrutura do AspNet Identity. A outra é a nossa própria implementação de qualquer outra coisa relacionada ao usuário. Prefiro esta solução do que estender o esquema ApsNet, porque posso lidar facilmente com alterações futuras no AspNet Identity e, ao mesmo tempo, a separação deixa claro para os programadores que "nossas próprias informações do usuário" vão para o esquema de usuário específico que definimos .
fonte
Huh, passou bastante tempo com um problema com contextos de banco de dados separados para cada esquema de banco de dados, espero que ajude outra pessoa ...
Recentemente, comecei a trabalhar em um projeto que possuía um banco de dados com 3 esquemas (primeira abordagem do banco de dados), um deles para gerenciamento de usuários. Havia um contexto de banco de dados estruturado em cada esquema separado. Obviamente, os usuários também estavam relacionados a outros esquemas, por exemplo. O esquema KB teve uma tabela Tópico, que foi "criado por", "modificado pela última vez por" etc.) FK para esquema de identidade, tabela appuser.
Esses objetos foram carregados separadamente em C #; primeiro, o tópico foi carregado de 1 contexto; os usuários foram carregados por meio de IDs de usuários do outro contexto de banco de dados - nada bom, é preciso corrigir isso! (semelhante ao uso de vários dbcontexts no mesmo banco de dados do EF 6 )
Primeiro, tentei adicionar instruções FK ausentes do esquema de identidade ao esquema da KB, ao EF modelBuilder no contexto da base de dados da KB. O mesmo que se houvesse apenas 1 contexto, mas eu o separei para 2.
Não funcionou, porque o contexto kb db não tinha nenhuma informação sobre o objeto usuário, e o postgres retornou um erro
relation "AppUsers" does not exist
. A instrução Select não tinha informações adequadas sobre esquema, nomes de campos etc.Eu quase desisti, mas notei uma opção "-d" ao executar
dotnet ef dbcontext scaffold
. Sua abreviação de -data-annotations - Use atributos para configurar o modelo (sempre que possível). Se omitido, apenas a API fluente é usada. Com essa opção especificada, as propriedades do objeto foram definidas não no contexto dbOnModelCreating()
, mas no próprio objeto, com atributos.Dessa forma, a EF obteve informações suficientes para gerar uma instrução SQL adequada com nomes e esquemas de campos adequados.
TL; DR: contextos de banco de dados separados não lidam bem com relações (FKs) entre eles, cada contexto possui apenas informações sobre suas próprias entidades. Ao especificar "-data-anototations"
dotnet ef dbcontext scaffold
, essas informações não são armazenadas em cada contexto separado, mas nos próprios objetos do banco de dados.fonte