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 oQueryDSL. 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.