Hibernate - Vale a pena abstrair ainda mais?

Estudando sobre Domain Driven Design aprendi sobre Repository, Criteria, etc. Juntamente com os Data Mappers (Famosos DAOs em Java) catalogados por Fowler, percebi que o Hibernate/JPA aparentemente utilizou-se dessa ideia para a criação do seu framework.

Concluí então, que utilizando Hibernate não preciso criar RepositorioXXX ou Criterias ou DAOs já que o Hibernate tem tudo isso a disposição através da Session/EntityManager, Criteria, Dialeto do Banco de Dados e a geração automática das instruções SQL.

Eu sei que a Session/EntityManager é muito genérico, serve como repositório de todos os objetos, diferente de um RepositorioCliente por exemplo, mas mesmo assim, ainda vou precisar em algum cenário criar classes para o padrão Repository quando utilizo Hibernate ?

Utilizando a Session/EntityManager na Fachada de Serviços ou até mesmo dentro de alguma Entity(DDD) em alguma operação de negócio que precise de dados, ao meu ver estou utilizando implicitamente todos esses padrões e implementando da maneira correta.

Sugestões ?

Eu tenho usado Repositorys diretamente de dentro das Entitys, e dentro do Repository uso diretamente o Hibernate, sem mais abstrações.

Pois é. Mas é isso que eu acho não fazer sentido.

Por exemplo:

public class RepositorioUsuario {
   private EntityManager em;
   public void salvar(Usuario u) {
      em.persist(u);
   }
}

O que eu ganhei com isso ? Nada.

Virou um delegador apenas.

Neste caso da a impressão mesmo de apenas uma camada a mais, agora vc já parou para pensar em casos mais complexos?

Eu uso o repository só para buscas… para persistir e para mergear uso o EntityManager… pra mim o EM, já é uma abstração…

Por isso eu tenho um AbstractRepository com as principais funções de CRUD. Ai se não preciso nada além do CRUD, basta extenter e não fazer mais nada.

o problema de você não ter repository é correr o risco de duplicar código. Por exemplo, você em várias partes do sistema tem que obter o usuário à partir do email. Se você não tem um Repository de Usuários, terá que construir consultas para buscar o usuário pelo email por varias partes do sistema.

Utiliza Spring com HibernateDaoSuport vai ficar bem mais facil de trabalhar com Hibernate, ai ele controla Session/Entity Manager para vc!

Os Repositorys acabam sendo usados para buscas mesmo, acho que é esta a idéia.

Como eu disse, eu prefiro ter um AbstractRepository<T> com os métodos de CRUDs básicos, para evistar o uso do EM diretamente, mas também não vejo problemas nisso.

Até entendi mas ai você ficaria com repositórios incompletos e/ou dupicados. Ex: RepositorioConta só para pesquisa nas contas e o EntityManager para o crud. Não ficaria confuso essas classes no seu Domain Model ? Teoricamente caso eu queira utilizar o seu RepositorioConta eu vou procurar uma opção de salvar minha conta ali, entende ?

Acho que ainda não ta legal …

Você acha que o EntityManager é uma classe do Domain Model ou da Infra?

O Repository faz além de buscas com de filtros sql.

Do tipo.

Busque todas as casas com 3 quartos onde o primeiro quarto tenha a cor rosa e a cozinha tenha uma janela para um bosque com uma macieira e um cavalo branco (apenas um cavalo) :smiley: .

Uma busca dessas certamente não vai poder ser feita apenas com joins e filtros no where…

Aí que o repository entra efetivamente.

Entende ??

@rodrigoy
Você tocou no ponto. Tecnicamente EntityManager seria um Repository so que genérico. Porém, a implementação que o Hibernate/JPA fez fica com cara de infra. Então fica parecendo uma mistura das duas coisas, ou seja, responsabilidade demais. O cheiro de infra é tão grande por causa dos métodos persist(), merge(), ao invés de um adicionar() por exemplo.

Mas de qualquer maneira ainda acho meio esquisito você ter um Repository que não tem as opções adicionar() e remover() por exemplo, ficando somente com consultas. Ta certo que poderia ter delegando para o EntityManger fazer isso mais sei lá, parece uma coisia meio bacalhau entende ? O que você acha ?

@nbluis
Isso foi falado anteriormente pelo rodrigoy, porém o problema é justamente este. Um Repository segundo a definição é onde a Entity fica guardada então fica estranho eu ter um RepositoryConta para buscar uma conta e depois quando eu for adicionar uma nova conta eu não poder usar esse Repository. Deveria se único para esse Entity.

Como assim não pode chamar o repository?

Vc chama o repository para adicionar, remover ou qualquer coisa dessas.

Já parou para pensar no fato de que nem todas as suas entidade podem ter o adicionar(persist) ?
O Repository é quem controla isso.

Para as consultas você pode utilizar Restrictions, tanto como filtro, como ordenação!

Não quis dizer que não pode, só quis dizer que vai ser apenas uma delegação, ou seja, um método quase burro.

Correto. O que acontece é que o EntitManager me dá todas essas operações e esse Repository sugerido como ficaria sendo que o Hibernate já tem a sua API Criteria ? Teoricamente Quando implementamos um Repositpry temos Criteria também. Não já é isso que o Hibernate faz ?

Acho que não. Os DAOs ainda são válidos, já os Repositorios nem tanto…

Fica meio estranho acessar o EntityManger de dentro de Entities.

O seu repositório pode cuidar de operações mais complexas do que simplesmente fazer um CRUD ou uma busca simples. Para formar um agregado, por exemplo, você pode realizar mais de uma consulta no banco.

Um repositório é um elemento ativo no negócio e na modelagem, não é uma ferramenta de acesso a dados. Ele pode ser modelado com comportamento (métodos) que fazem sentido quando colocados em um diagrama do domínio, pois o objeto em sí pertence ao domínio. Um EntityManager não pertence a domínio algum, e seus métodos não são Ubiquitous.

O repositório tbm é um bom lugar para você definir seus contratos quando se interage com algo da persistencia (e retornar uma exception para seu cliente da camada). Isso parece melhor do que retornar true/false, null, 1/0, e outras bizarrices.

Colocar EntityManager diretamente nas entidades parece um grande acoplamento entre meios de persistencia e objetos de negócio.

@Lezinho
Concordo com você. Então o que eu disse sobre ter no Repository um adicionar que chama o persist() do EntityManager tornando esses métodos do Repository apenas um método que delega a tarefa e era isso que não estava me agradando muito. Mas parece que não tem outro jeito.

Mas de qualquer maneira a idéia do EntityManager não seria implementar um Repository só que genérico ? Eu entendo que fica mais Ubiquitous mas não sei se vale muito a pena abstrair isso em todos os casos. Talvez na maioria dos casos não seja necessário. E isso justamente que eu to me perguntando se tem algum caso que vou precisar realmente …

Exemplos ?

Parta do pressuposto que é natural da entidade ela ser “persistente”, dessa forma, não é comum que uma entidade “salve” ela própria ou outras entidades dentro do comportamento da própria entidade. Minhas entidades não dependem do EntityManager, mas minhas façades sim…

Dado o paradigma atual uma das grandes responsabilidades da camada de aplicação é concentrar o controle de transação, seja por AOP, Anotações, Contâiner, etc… Assim sendo, é na camada de aplicação que está os manager.persist e manager.merge.

Lembre-se também: só usamos o EntityManager por causa de ORM, e nossas entidades não sabem disso.

Concordo um pouco com o que o Rodrigo disse. Os repositorios trazem bastante valor para agregados e pesquisas complexas. Considerando que você não está usando ActiveRecord, você não vai precisar chamar save/persist/merge dentro dos seus objetos de domínio. Aí o Repositório não precisaria ter o adicionar() que só delega.

Minha opinião pessoal é de que não é tão ruim ter métodos do Repositório que apenas delegam se você não quiser expor a Session/EntityManager. O Repositório nesses casos fica sendo um “Adapter”, mas concordo que isso é um pouco burocrático…

De qq forma, Java é burocrático mesmo! :twisted: