Entity Framework com sistemas grandes - como dividir modelos?

49

Estou trabalhando com um banco de dados do SQL Server com mais de 1.000 tabelas, outras centenas de exibições e vários milhares de procedimentos armazenados. Estamos procurando começar a usar o Entity Framework para nossos projetos mais recentes e estamos trabalhando em nossa estratégia para isso. A coisa em que estou pendurado é a melhor forma de dividir as tabelas em modelos diferentes (EDMX ou DbContext se formos primeiro o código). Eu posso pensar em algumas estratégias logo de cara:

  • Dividido por esquema
    Temos nossas tabelas divididas provavelmente em uma dúzia de esquemas. Nós poderíamos fazer um modelo por esquema. Isso não é perfeito, porque o dbo ainda acaba sendo muito grande, com mais de 500 tabelas / visualizações. Outro problema é que certas unidades de trabalho acabarão tendo que fazer transações que abrangem vários modelos, o que aumenta a complexidade, embora eu assuma que a EF torna isso bastante simples.
  • Dividido por intenção
    Em vez de se preocupar com esquemas, divida os modelos por intenção. Portanto, teremos modelos diferentes para cada aplicativo, projeto, módulo ou tela, dependendo da granularidade desejada. O problema que vejo com isso é que há certas tabelas que inevitavelmente precisam ser usadas em todos os casos, como User ou AuditHistory. Adicionamos esses a todos os modelos (viola DRY, ou são aqueles em um modelo separado que é usado por todos os projetos?
  • Não divida nada - um modelo gigante
    Isso é obviamente simples de uma perspectiva de desenvolvimento, mas a partir de minha pesquisa e minha intuição, parece que ele poderia funcionar terrivelmente, tanto em tempo de design, em tempo de compilação e possivelmente em tempo de execução.

Qual é a melhor prática para usar o EF em um banco de dados tão grande? Especificamente, quais estratégias as pessoas usam ao projetar modelos contra esse volume de objetos de banco de dados? Existem opções que eu não estou pensando que funcionam melhor do que o que eu tenho acima?

Além disso, isso é um problema em outros ORMs como o NHibernate? Em caso afirmativo, eles vêm com soluções melhores do que a EF?

    
por RationalGeek 07.09.2012 / 22:18
fonte

4 respostas

30

Pessoalmente, tentei criar um enorme esquema para todas as minhas entidades em um projeto bastante complexo, mas pequeno (~ 300 tabelas). Nós tínhamos um banco de dados extremamente normalizado (5ª forma de normalização (digo vagamente)) com muitos relacionamentos "muitos para muitos" e aplicação extrema de integridade referencial.

Também usamos uma estratégia de "instância única por solicitação" que também não estou convencida de ajuda.

Ao fazer listas, pesquisas e pesquisas simples, razoavelmente definidas, "explicitamente definidas", geralmente é aceitável. Mas quando começamos a nos aprofundar em relacionamentos profundos, o desempenho pareceu diminuir drasticamente. Comparado a um procedimento armazenado neste exemplo, não houve comparação (claro). Tenho certeza de que poderíamos ter ajustado a base de código aqui e ali para melhorar o desempenho, no entanto, neste caso, só precisávamos de aumento de desempenho sem análise devido a restrições de tempo, e voltamos ao procedimento armazenado (ainda mapeado através da EF, porque a EF forneceu resultados strongmente tipados), nós só precisávamos disso como um recuo em algumas áreas. Quando tivemos que percorrer todo o banco de dados para criar uma coleção (usando .include () unsparingly), o desempenho estava consideravelmente degradante, mas talvez estivéssemos perguntando muito ..

Portanto, com base em minha experiência, recomendo criar um .edmx por intenção. Gere apenas o que você vai usar com base no escopo dessa necessidade. Você pode ter alguns arquivos .edmx com escopo menor para tarefas propostas e, em seguida, alguns grandes, em que é necessário atravessar relacionamentos complexos para criar objetos. Não tenho certeza de onde é esse ponto mágico, mas tenho certeza que tem um ... rsrs ...

Honestamente, apesar de algumas armadilhas que nós vimos chegando (cruzamento complexo), o enorme .edmx funcionou bem de uma perspectiva de "trabalho". Mas você terá que tomar cuidado com a mágica de "conserto" que o contexto faz por trás da cena, se você não a desabilitar explicitamente. Além de manter o .edmx em sincronia quando as alterações no banco de dados são feitas ... algumas vezes foi mais fácil limpar toda a superfície e recriar as entidades, o que demorou 3 minutos, então não foi nada demais.

Isso foi tudo com o EntityFramework 4.1. Eu estaria realmente interessado em ouvir sobre sua escolha final e experiência também.

E em relação a sua pergunta sobre o nHibernate, é uma questão de latas de vermes, na minha opinião, você vai latir nos dois lados da cerca ... Eu ouço muita gente batendo a EF para bater sem trabalhando através dos desafios e entendendo as nuances exclusivas da própria EF .. e embora eu nunca tenha usado o nHibernate em produção, geralmente, se você tiver que criar manualmente e explicitamente coisas como mapeamentos, você terá um controle mais finito, no entanto , se você pode arrastar e soltar, gerar e iniciar o CRUD e consultar usando o LINQ, eu poderia dar uma porcaria sobre granularidade.

Espero que isso ajude.

    
por 07.09.2012 / 22:41
fonte
12

Deixem-me começar por um simples esclarecimento: não tenho experiência com uma base de dados tão grande, pelo que o resto da minha resposta não se baseia no exemplo do mundo real.

Então você tem um banco de dados GRANDE e quer usá-lo com o ORM / EF. Eu iria com a segunda escolha. Aqui está a minha explicação simples porque:

  • O mapeamento adiciona complexidade. Não há necessidade de adicionar complexidade às entidades que seu aplicativo / projeto / módulo atual nunca precisa, mas não torna a granularidade muito baixa. Ter um conjunto separado de mapeamento por tela também não o ajudará.
  • Você deseja alcançar a unidade de trabalho. Você deve ser capaz de especificar o que o módulo de tabelas precisa na maioria dos casos (não é necessário em todos os casos). Se você colocar essas tabelas em um único conjunto de mapeamento, poderá manipular a leitura e a modificação de dados por uma única instância de contexto - eis qual deve ser seu destino final.
  • Não sei exatamente o que você quer dizer com modelo, mas mesmo com conjuntos de mapeamento diferentes, é possível compartilhar classes entre conjuntos de mapeamento usando os mesmos tipos de entidade. Portanto, se você usar a tabela de usuários em dois módulos, não precisará de duas classes de usuário para representar as mesmas. Você ainda pode usar uma única tabela e no caso de mapeamento de código (também conhecido como code-first) você pode definir o mapeamento uma vez e carregá-lo em vários conjuntos de mapeamento para que o princípio DRY não seja violado, mas a abordagem code-first tem mais limitações para exibições e procedimentos armazenados. EDMX torna isso mais difícil. Ainda é possível reutilizar classes, mas é impossível reutilizar o mapeamento.
  • E quanto às consultas entre módulos? Estas perguntas podem acontecer, mas para ser honesto, nem tudo deve ser tratado pela EF. Você pode aproveitar o EF para casos comuns para simplificar o acesso regular a dados, mas se você precisar de uma consulta especial que junte tabelas pertencentes a 5 módulos diferentes, basta executá-lo diretamente ou agrupá-lo no procedimento armazenado. A substituição de 100% do acesso a dados nativos pode ser difícil, complexa e contraproducente.
  • O último ponto é simplesmente prático: não acredito que o ferramental VS esteja pronto para trabalhar com um conjunto tão grande de objetos - não no designer, nem mesmo com a ferramenta de importação. Eu costumava trabalhar em um banco de dados muito grande com acesso a dados tradicional e projeto de banco de dados SQL no VS2008 - a experiência do usuário com um projeto complexo era muito ruim. Você deve manter o número de tabelas usadas baixo - o limite para o designer deve estar entre 100-200, mas até 100 tabelas tratadas por contexto único (conjunto de mapeamento) soa como muita responsabilidade para uma classe (suponha que você tenha 100 propriedades definidas exposta no contexto - não parece um bom design).
por 07.09.2012 / 23:40
fonte
3

Eu diria que você não pode decidir esse tipo de pergunta a partir de uma perspectiva técnica. Eu recomendo que você construa sua arquitetura com base em seus casos de uso (histórias de usuários, etc.). Primeiro, encontre seus objetos de negócios. Um objeto de entidade não é, por padrão, um objeto de negócios. Típico você terá um objeto de negócios na frente dos objetos de entidade. Em seguida, você pode decidir de forma incremental o que realmente precisa, com base nos requisitos do usuário.

"Um bom arquiteto maximiza o número de decisões não tomadas." Robert C. Martin

link

    
por 10.09.2012 / 20:40
fonte
2

Eu uso uma abordagem híbrida - o material OLTP é tratado pelo EF enquanto operações pesadas como inserções em lote, atualizações em massa, consultas de relatórios, etc. são tratadas por Procs Armazenados. Isso também torna o caminho de migração mais fácil se você não estiver fazendo uma re-gravação completa da sua camada de dados de uma só vez.

    
por 11.09.2012 / 21:23
fonte