Skip to main content

Implementação do Repostitory

A implementação do repostitory serve como a camada de ligação entre a abstração definida na camada de domínio e a base de dados física. Utilizando o padrão Repository, isolamos a lógica de acesso a dados do resto da aplicação, o que facilita a manutenção e a escalabilidade.

Exemplo Simples

package com.webpublico.ead.infrastructure.adapter.persistence.repository.academico;

import br.com.archbase.ddd.infraestructure.persistence.jpa.repository.ArchbaseCommonJpaRepository;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.webpublico.ead.domain.model.academico.Topico;
import com.webpublico.ead.domain.repository.academico.TopicoRepository;
import com.webpublico.ead.infrastructure.adapter.persistence.BaseRepositoryImpl;
import com.webpublico.ead.infrastructure.persistence.entity.academico.QTopicoEntity;
import com.webpublico.ead.infrastructure.persistence.entity.academico.TopicoEntity;
import com.webpublico.ead.infrastructure.persistence.repository.jpa.academico.TopicoJpaRepository;
import org.springframework.stereotype.Component;

@Component
public class TopicoRepositoryImpl extends BaseRepositoryImpl<TopicoEntity, Topico> implements TopicoRepository {

private final TopicoJpaRepository repository;

public TopicoRepositoryImpl(TopicoJpaRepository repository) {
this.repository = repository;
}

@Override
protected Class<TopicoEntity> getEntityClass() {
return TopicoEntity.class;
}

@Override
protected EntityPathBase<TopicoEntity> getEntityPath() {
return QTopicoEntity.topicoEntity;
}

@Override
protected ArchbaseCommonJpaRepository<TopicoEntity, String, Long> getRepository() {
return repository;
}

}

Exemplo com Relacionamento

Para repostitories que gerenciam entidades com relacionamentos complexos, a implementação pode incluir mapeamentos e recuperações adicionais, como neste exemplo onde um tópico pode ter um tópico anterior.

package com.webpublico.ead.infrastructure.adapter.persistence.repository.academico;

import br.com.archbase.ddd.infraestructure.persistence.jpa.repository.ArchbaseCommonJpaRepository;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.webpublico.ead.domain.model.academico.Topico;
import com.webpublico.ead.domain.repository.academico.TopicoRepository;
import com.webpublico.ead.infrastructure.adapter.persistence.BaseRepositoryImpl;
import com.webpublico.ead.infrastructure.adapter.persistence.mapper.academico.TopicoPersistenceMapper;
import com.webpublico.ead.infrastructure.persistence.entity.academico.QTopicoEntity;
import com.webpublico.ead.infrastructure.persistence.entity.academico.TopicoEntity;
import com.webpublico.ead.infrastructure.persistence.repository.jpa.academico.TopicoJpaRepository;
import org.springframework.stereotype.Component;

@Component
public class TopicoRepositoryImpl extends BaseRepositoryImpl<TopicoEntity, Topico> implements TopicoRepository {

private final TopicoPersistenceMapper mapper;
private final TopicoJpaRepository repository;

public TopicoRepositoryImpl(TopicoPersistenceMapper mapper, TopicoJpaRepository repository) {
super(mapper);
this.mapper = mapper;
this.repository = repository;
}

public Topico salvar(Topico topico) {
TopicoEntity nivelAnterior = obterReferenciaNivelAnteriorTopicoEntity(topico);
TopicoEntity topicoEntity = mapper.mapToEntity(topico, nivelAnterior);
topicoEntity.setNivelAnterior(nivelAnterior);
return super.salvar(topicoEntity);
}

private TopicoEntity obterReferenciaNivelAnteriorTopicoEntity(Topico topico) {
String nivelAnteriorTopicoId = topico.getNivelAnteriorTopicoId();
if (nivelAnteriorTopicoId != null) {
return entityManager.getReference(TopicoEntity.class, nivelAnteriorTopicoId);
}
return null;
}

@Override
protected Class<TopicoEntity> getEntityClass() {
return TopicoEntity.class;
}

@Override
protected EntityPathBase<TopicoEntity> getEntityPath() {
return QTopicoEntity.topicoEntity;
}

@Override
protected ArchbaseCommonJpaRepository<TopicoEntity, String, Long> getRepository() {
return repository;
}

}

Considerações Adicionais

  • Localização do Repostitory: Repostitories estão localizados no pacote infrastructure.adapter.persistence.repository. Esta estrutura ajuda a manter a camada de infraestrutura claramente separada da lógica de domínio, seguindo os princípios da Arquitetura Hexagonal e da Clean Architecture.

  • Extensão de BaseRepositoryImpl: Esta classe base proporciona implementações genéricas para operações CRUD comuns, reduzindo a necessidade de reescrever código redundante em cada repostitory. Repositórios específicos podem estender esta classe para aproveitar essas implementações ou implementar comportamentos customizados conforme necessário.

  • Uso de QueryDSL: Para operações de consulta mais complexas que não são bem atendidas pelas operações CRUD padrão, utilizamos o QueryDSL. Isso permite consultas tipo-safe e dinâmicas que são fáceis de montar e manter.

  • Casos Especiais: Em certos cenários onde a lógica de negócio exige comportamentos muito específicos ou onde o desempenho é uma preocupação crítica, pode ser necessário implementar repostitories sem estender BaseRepositoryImpl. Nesses casos, a implementação deve, no mínimo, aderir ao contrato definido pela interface de repositório do domínio.

  • Conveção de nome: A nomenclatura das classes de repostitory segue o padrão [Entidade]RepositoryImpl, e as interfaces no domínio seguem o padrão [Dominio]Repository. Isso mantém a consistência e facilita a localização dos componentes relacionados ao repostitory dentro do projeto.

Finalizando

A estruturação e implementação dos repostitory desta forma não apenas organiza o código de maneira eficiente, mas também promove uma separação clara de responsabilidades, tornando o sistema mais fácil de testar, manter e evoluir. A escolha de padrões e tecnologias para a camada de persistência é guiada pelo objetivo de manter o domínio limpo e focado na lógica de negócio, enquanto detalhes específicos de implementação são isolados na infraestrutura.