Armadilhas do Design Orientado a Domínios com o Entity Framework

11

Muitos tutoriais sobre DDD que estudei são principalmente sobre teoria. Todos eles têm exemplos de código rudimentares (Pluralsight e similares).

Na web, também existem algumas tentativas de algumas pessoas de criar tutoriais que cobrem DDD com EF. Se você começar a estudá-los apenas brevemente - notará rapidamente que eles diferem muito um do outro. Algumas pessoas recomendam manter o aplicativo mínimo e evitar a introdução de camadas adicionais, por exemplo, repositório no EF , outras estão gerando camadas extras, muitas vezes até violando o SRP ao injetar DbContextem Raízes Agregadas.

Peço desculpas se estiver fazendo uma pergunta baseada em opinião, mas ...

Quando se trata de prática - o Entity Framework é um dos ORMs mais poderosos e amplamente utilizados. Infelizmente, você não encontrará um curso abrangente cobrindo o DDD.


Aspectos importantes:

  • O Entity Framework traz UoW e Repository ( DbSet) fora da caixa

  • com a EF, seus modelos têm propriedades de navegação

  • com a EF, todos os modelos estão sempre disponíveis desativados DbContext(eles são representados como a DbSet)

Armadilhas:

  • você não pode garantir que seus modelos filhos sejam afetados apenas pela Raiz agregada - seus modelos têm propriedades de navegação e é possível modificá-los e chamardbContext.SaveChanges()

  • com DbContextvocê, você pode acessar todos os seus modelos, contornando a raiz raiz agregada

  • você pode restringir o acesso aos filhos do objeto raiz via ModelBuilderno OnModelCreatingmétodo , marcando-os como campos - ainda não acredito que seja o caminho certo para obter DDD, além de ser difícil avaliar que tipo de aventuras isso pode levar no futuro ( bastante cético) )

Conflitos:

  • sem implementar outra camada de repositório que retorne agregado, não podemos nem mesmo resolver parcialmente as armadilhas acima mencionadas

  • implementando uma camada extra de repositório, estamos ignorando os recursos internos do EF (todos DbSetjá são um repositório ) e complicando demais o aplicativo


Minha conclusão:

Perdoe minha ignorância, mas com base nas informações acima - o Entity Framework não é adequado para o Design Orientado a Domínio ou o Design Orientado a Domínio é uma abordagem imperfeita e obsoleta .

Eu suspeito que cada uma das abordagens tem seus méritos, mas agora estou completamente perdida e não tenho a menor idéia de como reconciliar EF com DDD.


Se eu estiver errado - alguém poderia pelo menos detalhar um conjunto simples de instruções (ou até mesmo fornecer exemplos decentes de código) de como proceder com o DDD com a EF, por favor?

Alex Herman
fonte
Eu detalhei as etapas aqui de acordo com meu entendimento de como a EF funciona. Ainda assim, essas etapas não tratam do problema de acessar crianças pela navegação. propriedades ou por DbSets fora de DbContext.
Alex Herman

Respostas:

8

DDD e EF têm pouco ou nada a ver um com o outro.

DDD é um conceito de modelagem. Significa pensar no domínio, nos requisitos de negócios e modelá-los. Especialmente no contexto da orientação a objetos, significa criar um design que reflita as funções e os recursos comerciais.

EF é uma tecnologia de persistência. Ele se preocupa principalmente com dados e registros de banco de dados.

Estes dois são fortemente divorciados. Um design DDD pode usar EF de alguma forma sob o capô, mas os dois não devem interagir de nenhuma outra maneira.

Algumas interpretações do Design Orientado a Domínio realmente defendem a modelagem de dados, e acho que é disso que se trata sua pergunta. Nesta interpretação, "Entidades" e "Objetos de Valor" são essencialmente apenas titulares de dados sem função, e o design se preocupa com quais propriedades elas mantêm e qual relação elas têm entre si. Nesse contexto, DDD vs. EF pode surgir.

Essa interpretação, no entanto, é falha, e eu recomendo fortemente ignorá-la por completo.

Concluindo : DDD e EF não são mutuamente exclusivos, eles são irrelevantes um para o outro, desde que você faça modelagem de objeto adequada e não modelagem de dados. Os objetos DDD não devem, de forma alguma, ser artefatos EF. Entidades DDD não devem ser "entidades" EF, por exemplo. Dentro de alguma função relevante para os negócios, um design DDD pode usar EF com alguns objetos de dados relacionados, mas esses devem estar sempre ocultos em uma interface orientada a comportamento relevante para os negócios.

Robert Bräutigam
fonte
11
A EF apenas economiza tempo. O rastreamento de alterações e a persistência de agregados é onde a EF já ajuda bastante. Infelizmente, atualmente não há como definir a forma dos agregados no nível de configuração.
Pavel Voronin
6

Trate o EF pelo que é, ou seja, a biblioteca de acesso a dados, que é apenas um pouco mais fortemente tipada que o ADO.NET bruto. Eu não recomendaria modelar seu domínio usando classes de entidade EF, assim como não recomendaria modelar domínio usando DataSet ou DataTable brutos.

Entendo que o EF está sendo vendido como um atalho entre o acesso ao banco de dados e a modelagem de domínio. No entanto, essa abordagem é intrinsecamente falha, pois trata de dois problemas amplamente não relacionados. Houve outras tentativas no .NET de fazer uma classe executar algumas coisas completamente não relacionadas (por exemplo, .NET Remoting) e elas não terminaram bem.

Faça o DDD usando classes POCO e não permita que o esquema do banco de dados conduza seu design. Mantenha a EF dentro da camada de repositório / persistência e não permita que as entidades da EF vazem para fora.

Cola
fonte
5

O Entity Framework coloca o UoW e o Repositório (DbSet) fora da caixa

Não.

As abstrações do Entity Framework foram criadas com o ORM, e não o DDD, em mente. A DbSetabstração em qualquer versão do Entity Framework não DbContextchega nem perto da simplicidade de um repositório DDD - para não mencionar o que expõe um zilhão de coisas mais do que um UnitOfWork.

Aqui está uma lista não exaustiva de elementos no resumo do EF Core 2.1 DbSet<TEntity>que não precisamos no DDD:

  • Attach(TEntity) e todos os seus irmãos
  • Find(Object[])
  • Update(TEntity) e todos os seus irmãos
  • Implementando IQueryable

Além de arrastar dependências desnecessárias com elas, elas obscurecem a intenção de um Repositório que normalmente expõe um comportamento de coleção muito simples. Além disso, as abstrações com vazamentos são uma tentação constante para os desenvolvedores se juntarem demais à EF e uma ameaça à Separação de Preocupações.

Conclusão: você deve agrupar essas gorduras em conceitos agradáveis ​​e simplificados e adivinhe, o que significa introduzir classes extras.

Um exemplo relativamente sólido do que você pode fazer com EF e DDD (embora alguns pontos de vista expressos sejam discutíveis): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

outros estão decididamente gerando camadas extras, muitas vezes até violando o SRP, injetando DbContext em raízes agregadas

Realmente não vejo a conexão entre as duas partes desta frase. Não importa a abordagem, existe no DDD uma coisa chamada Serviço de Aplicativo e é aí que você manipula a Unidade de Trabalho / Repositório (ou DbContext). Não em raízes agregadas.

Embora possa ser uma abordagem válida se for uma troca educada, a recente tendência anti-Repositório, "Minimalismo de Entidade da Estrutura", é ilusória. Ele culpa os padrões DDD pelo atrito que ocorre com o Entity Framework, quando na verdade são os criadores da EF que não fizeram nada para tornar sua estrutura compatível com as melhores práticas prontas para uso. O tempo todo eles estão se acoplando firmemente a essa estrutura com todos os problemas em termos de segurança e manutenção de código que podem ocorrer.

guillaume31
fonte
2

Conflitos:

sem implementar outra camada de repositório que retorne agregado, não podemos nem> parcialmente resolver as armadilhas acima mencionadas

implementando uma camada extra de repositório, estamos ignorando os recursos internos do EF (todo DbSet já é um repositório) e complicando demais o aplicativo

Eu usei uma abordagem em que cada agregado obtém seu próprio DBContext, mapeando exatamente o que é necessário para o agregado. Eu acho que isso também foi descrito por Julie Lerman.

Isso funcionou muito bem, mas pode não ser suficiente para modelos mais interessantes, nos quais você não deseja vincular seus conceitos às suas entidades.

mvg
fonte
Visto este vídeo, bem dddcommunity.org/ddd-contributors/...
Alex Herman
Existem benefícios na abordagem DBContext por agregado? Essa é a maneira padrão de implementar DDD com EF?
Alex Herman
Julie Lerman não quis dizer DbContext por contexto limitado?
Mvision 08/08/19
0

Apenas gostaria de compartilhar uma possível solução para consideração:

  1. evite referenciar o projeto EF diretamente na camada de serviço

  2. crie uma Camada de Repositório extra (usa o projeto EF e retorna Raiz Agregada)

  3. referencie o projeto Repository Layer in Service Layer

Arquitetura :

  • UI

  • Camada Controladora

  • Camada de serviço

  • Camada de Repositório

  • Estrutura de entidade

  • Projeto Principal (contém modelos EF)


As armadilhas que vejo com essa abordagem:

  • se um Repositório retornar Raiz Agregada, não como a árvore do modelo EF (por exemplo, retornamos um objeto mapeado) - estamos perdendo a capacidade da EF de rastrear alterações

  • se a Raiz Agregada for um modelo EF - todas as suas propriedades de navegação ainda estão disponíveis , mesmo que não possamos lidar com DbContextisso (não fazemos referência ao projeto EF na Camada de Serviço)

Alex Herman
fonte