DDD - O repositório de uma raiz agregada manipula a gravação de agregados?

27

Estou usando uma abordagem semelhante ao DDD para um módulo greenfield de um aplicativo existente; não é 100% DDD devido à arquitetura, mas estou tentando usar alguns conceitos de DDD. Eu tenho um contexto limitado (acho que esse é o termo apropriado - ainda estou aprendendo sobre DDD), composto por duas entidades: Conversatione Message. A conversa é a raiz, pois uma Mensagem não existe sem a conversa e todas as mensagens no sistema fazem parte de uma conversa.

Eu tenho uma ConversationRepositoryclasse (embora seja realmente mais como um Gateway, eu uso o termo "Repositório") que encontra Conversas no banco de dados; quando encontra uma conversa, também cria (via fábricas) uma lista de mensagens para essa conversa (exposta como uma propriedade). Essa parece ser a maneira correta de lidar com as coisas, pois não parece haver necessidade de uma MessageRepositoryclasse completa, pois ela só existe quando uma Conversa é recuperada.

No entanto, quando se trata de salvar uma mensagem, é responsabilidade do ConversationRepository, pois é a raiz agregada da mensagem? O que quero dizer é que eu deveria ter um método no ConversationRepository chamado, digamos, AddMessageque pega uma mensagem como parâmetro e a salva no banco de dados? Ou devo ter um repositório separado para localizar / salvar mensagens? A coisa lógica parece ser um repositório por entidade, mas também ouvi "Um repositório por contexto".

Wayne Molina
fonte

Respostas:

25

O livro azul é definitivamente vale a pena ler se você quiser tirar o melhor proveito da abordagem DDD. Os padrões DDD não são triviais e aprender a essência de cada um deles ajudará você a ponderar quando usar qual padrão, como dividir seu aplicativo em camadas, como definir seus Agregados e assim por diante.

O grupo de duas entidades que você mencionou não é um contexto vinculado - provavelmente é um agregado. Cada agregado possui uma raiz agregada, uma entidade que serve como um único ponto de entrada no agregado para todos os outros objetos. Portanto, nenhuma relação direta entre uma Entidade e outra Entidade em outro Agregado que não seja a Raiz Agregada.

Repositórios são necessários para se apossar de entidades que não são facilmente obtidas através da travessia de outros objetos. Repositórios geralmente contêm Raízes Agregadas, mas também pode haver Repositórios de Entidades regulares.

No seu exemplo, a Conversa parece ser a Raiz Agregada. Talvez as conversas sejam o ponto de partida do seu aplicativo ou talvez você queira consultá-las com critérios detalhados para que não fiquem satisfatoriamente acessíveis através da simples passagem de outros objetos. Nesse caso, você pode criar um repositório para eles, que dará ao código do cliente a ilusão de um conjunto de conversas na memória para consultar, adicionar ou excluir diretamente. Por outro lado, as mensagens são facilmente obtidas pela passagem de uma conversa, e você pode não querer recebê-las de acordo com critérios detalhados, apenas todas as mensagens de uma conversa de uma só vez, para que elas não precisem de um Repositório.

O ConversationRepository desempenhará um papel na persistência de mensagens, mas não um papel direto como você mencionou. Portanto, nenhum AddMessage () no ConversationRepository (esse método pertence à própria Conversação), mas, sempre que o Repositório persistir em uma Conversa, é uma boa ideia persistir suas Mensagens ao mesmo tempo, de forma transparente, se você usar uma estrutura ORM como (N) Hibernate, usando SQL ad hoc, se você escolher, etc.

guillaume31
fonte
1
Se uma raiz agregada, como a Conversa, possui muitos tipos diferentes de entidades, como Mensagem, Coisa e Wingies, quando você salva uma conversa, por exemplo, ConversationRepo.save (conversa), como você sabe quais entidades precisam para ser salvo? No exemplo de pôsteres acima, apenas as entidades da mensagem precisam ser salvas. Você percorre todas as coleções possíveis na raiz agregada para encontrar entidades sem IDs?
Chris-richards
3

Você pode criar o ConversationService e injetar o IConversationRepository e IMessageRepository em seu construtor. Use repositórios para operações CRUD simples e serviços para todo o resto (armazenamento em cache, economia de lógica etc.)

šljaker
fonte
1
não está salvando o CRUD lógico?
Timothy Groote