Duvidas sobre Dao + Hibernate + Repository

[quote=rponte]Por isso eu disse “para a maioria dos casos”. Se você precisa de algo mais abstrato e que faça mais sentido ao teu modelo então use-o, nem que seja um método que revele a devida intenção para seu modelo.

Agora não é interessante fazer da exceção a regra.[/quote]

A regra, utilizando somente Hibernate(mas que JPA seria bem próximo a isso), seria algo do tipo:

class Pessoa{

public void inserir(Pessoa p){
   try{
   createSession();
   beginTransaction();
   session.save(p);
   tx.commit();
   session.close();
   }.....

Essa é a sua sugestão? Ou entendi errado?

class ColecaoDePessoas {

public void inserir(Pessoa p){
   try{
   createSession();
   beginTransaction();
   session.save(p);
   tx.commit();
   session.close();
   }.....

Pra que criar uma camada se você pode criar um objeto?

[quote=mochuara][code]
class ColecaoDePessoas {

public void inserir(Pessoa p){
try{
createSession();
beginTransaction();
session.save§;
tx.commit();
session.close();
}…
[/code]

Pra que criar uma camada se você pode criar um objeto?[/quote]

Então a questão é só nomenclatura? Colocar o sufixo DAO caracteriza um anti-pattern?

public class PessoaDAO{ public void inserir...

Sim, porque ColecaoDePessoas não é um DAO. Ele não lida com “data sources” mas com objetos “em memoria”.

[quote]A regra, utilizando somente Hibernate(mas que JPA seria bem próximo a isso), seria algo do tipo:

class Pessoa{

public void inserir(Pessoa p){
   try{
   createSession();
   beginTransaction();
   session.save(p);
   tx.commit();
   session.close();
   }.....

Essa é a sua sugestão? Ou entendi errado?[/quote]

Levando em consideração que sua classe Pessoa faz parte da sua Camada de Aplicação, sim, seria algo do tipo. Evidentemente que sem este “glue code” todo para controle transacional.

[quote=sergiotaborda][quote=ravisantos]

O problema aqui é, onde entraria os metodos findAllByExample, no Repository ou nos Dao’s?

Como podem ver estou um pouco confuso com estes dos Patterns.

Se alguem puder esclarecer agradeço.

[/quote]

Vamos lá (de novo)

Repositorio : objeto responsável por encontrar instancias de entidades. Se ele é responsável por encontrar , os métodos find ficam com ele. Obvio, não ?
DAO : objecto responsável por acessar dados em fontes de tecnologia diversa. Ele isola a tecnologia de persistencia. Normalmente é um por entidade. (DAO genérico é uma aberração da natureza).
DomainStore : objecto responsável por toda a persistencia do dominio (o nome diz tudo). Ele utiliza DAO por baixo dos panos mas o cliente não os vê.
É um domainstore por dominio.

Um repositorio pode usar DAO, mas é mais natural utilizar DomainStore porque ambos se relacionam ao dominio.

Hibernate : implementação “comercial” de um DomainStore especializado em persistencia em banco de dados.

Se vc usa o hibernate você está dizendo que a persistencia apenas pode acontecer em banco de dados ( em traços largos, porque em tese o hibernate é expansivel a outras midias… mas não existe isso ainda).

O Repositorio tem aquele interface que vc chama de DAO. Com add, remove, e os finds. O repositorio base tem o findByID e os findAll() que são mais utilizados.

Um repositorio especifico para Cliente, por exemplo tem mais métodos find especificos de Cliente. Por exemplo findBySellRegion(Region r), findByNetRetail(Money minRetail) , etc … um report, por exemplo, é um método find do respositorio.

É facil implementar estes métodos ? Não. Vc precisa usar truques como Specification para a paginação e FastLaneReader para a leitura rápida sem consumir muitos recursos. Repositoriy é a melhor forma de modelar acesso a dados do ponto de vista do core de negocio. ( O padrão repositorio é velho. O Fowler que inventou antes do DDD existir. Repositorio não implica em DDD).

Bom, mas como implementar isso ?

Vamos ver com hibernate primeiro.
Para cada método vc delega ao hibernate de forma semelhantes ou qe já tem. Vc pode ter um HibernateAbstractRepository que implementa o básico do add , remove , etc… que é sempre igual. Além disso vc precisa de um método protegido findByCriteria(Criteria c). Este método é o coração da coisa toda. Um ClienteRepository irá implementar os seus finds especificos criando criterios do hibernate e mandar para aquele método. Isso é simples e é facil acrescentar novos métodos find. Se vc precisar de paginação , fastlane ou outras coisas, vc precisa incrementar o findByCriteria para ser o suficientemente poderoso para todos esses cenários. Um bom padrão para isso é criar uma interface padrão para a resposta ( que não seja um list). eu costumo usar algo como

public interface QueryResult<T> {
   public T first();
   public Collection<T> all()
   public boolean isEmpty();
   public int count();
   public QueryResult subQuery(int first, int count);

}

Esta interface permite criar um relay entre a chamada ao método find do repositorio e a real execução da pesquisa. Permite que a pesquisa seja otimizada , pois um count() não precisa ser all().size() , pode ser um SELECT count FROM … e o subQuery é para permitir paginação sem ter que colocar isso no contrato do método find. Assim vc pode paginar qualquer resultado de qualquer método find.
moral da historia, um bom design OO ajuda muito.

Bom, blz. Vc tem o seus repositorios utilizando o hibernate. Mas e se quiser se livrar do hibernate e trocar por JPA (supondo que isso é possivel)?
Ai vc mantém o repositorio criandos critérios, mas agora, vc tem que implementar a API de critérios de forma independente do Hibernate e do JPA ou de qq outra coisa. Depois vc cria um RepositoryStrategy que contém as implementações reais de add, remove, findByCriteria. Todos os métodos do repositorio delegam à estratégia. E a estratégia delega ao mecanismo real do hibernate, jpa , etc… A estratégia é injetada no repistorio via construtor.

A estratégia irá traduzir o seu critério de pesquisa agnostico (que não depende da tecnologia subjacente) para um critério especifico ( do hibernate, do jpa ,etc…). A estratégia irá executar o mecanismo especifico e retornar os dados. É assim que vc isola a tecnologia de persistencia do repositorio em si.

Para o caso simples e cotidiano pode manter o hibernate atrelado ao repositorio e só abstrair o hibernate quando outro mecanismo aparecer/for necessário.

E o DAO ? O DAO vc esquece.
[/quote]

Olá Sérgio, depois dessa aula. Algumas duvidas ainda me restaram. Por exemplo este metodo findByCriteria retornaria o que ?

E essa interface quema implementaria, me interessei por essa interface mais ainda não sei como aplica-la na pratica. Sem querer pedir demais poderia dar um exemplo;

Obrigado!

Sim. Representa que você não soube atribuir corretamente a responsabilidade à classe.
É a mesma coisa que vc ter uma lista e chamar Pessoa.

Para o caso do DAO isso é comum hoje em dia. Eu chamo isso de Sindrome de DAO

O que vc acha que deve. O pessoal gosta de retornar List, mas eu acho melhor retorar algo como o QueryResult que demonstrei.
Como ele é muito simples aplicar o padrão FastLane Reader .

Suponho que esteja falando do QueryResult. Quem a implementa é a camada mais inferior capaz de entender T. Normalmente o Repositorio ou o DomainStore. Quando mais baixa a camada mais otimizada a leitura e mais rápido o sistema. Se poder ser implementada pelo cada que lê do banco tanto melhor. Normalmente com Hibernate este objecto é implementado pelo Repositorio ou por uma estratégia do Repositorio.

Lembre-se que o Repositorio não está origado a usar persistencia. Basta que ele use preservação de dados. Se os dados são fixos estes requisitos são dados de barato. Um exemplo é um RoleRepository que mantem as entidades Role que representam as permissões dos usuários. normalmente Vc carrega um Map < id , Role > com todos os roles. Ai vc tem finds. Como tudo está na memoria, a otimização não é muita e vc acaba utilizando uma implementação baseada em colleções para o QueryResult.


public class CollectionQueryResult<T> implements QueryResult<T> {

           public CollectionQueryResult(Collection<? extends T> items ){
                    this.items = items;
           }

           public T first( ){
                 return this.items.isEmpty() ? null : this.items.iterator().next();
          }

           public Collection<T> all(){
                 return Collections.unmodifiableCollection(this.itens);
          }

          public boolean isEmpty(){
              return this.items.isEmpty() ;
          }

          public long count(){
                return this.items.size();
          }
}

Em uma situação de Fastalane Reader os métodos invocam as procuras directamente.
Por exemplo em JDBC puro o count invoca um SELECT Count, o empty retorna this.count() == 0 , o fisrt() retornar um Select * TOP 1 ( ou equivalente) e o all retorna um SELECT *

Esse é o poder do QueryResult. Ele pode ser implementado de trilhentas formas, mas para quem usa o repositorio e invoca, por exemplo:


QueryResult<XPTO> osBons =  repositorioXPTO.findAllActive();

for ( XPTO x : osBons.all() ){

     System.out.println(x.toString());
}

Isso é totalmente encapsulado. Mas mesmo assim é eficiente.

[quote=sergiotaborda]Sim. Representa que você não soube atribuir corretamente a responsabilidade à classe.
É a mesma coisa que vc ter uma lista e chamar Pessoa.[/quote]
Discordo.
Pra mim é pura e simples questão de nomenclatura. A responsabilidade do objeto continua exatamente o mesmo, antes de DDD e alguns outros padrões utilizavamos DAO para isso, agora mudamos o nome para fazer a mesma coisa.

[quote=Rafael Nunes][quote=sergiotaborda]Sim. Representa que você não soube atribuir corretamente a responsabilidade à classe.
É a mesma coisa que vc ter uma lista e chamar Pessoa.[/quote]
Discordo.
Pra mim é pura e simples questão de nomenclatura. A responsabilidade do objeto continua exatamente o mesmo, antes de DDD e alguns outros padrões utilizavamos DAO para isso, agora mudamos o nome para fazer a mesma coisa.
[/quote]

+1

E ainda estou esperando os exemplos… alguém tem algum exemplo de um repositório bem implementado?

[quote=Rafael Nunes][quote=sergiotaborda]Sim. Representa que você não soube atribuir corretamente a responsabilidade à classe.
É a mesma coisa que vc ter uma lista e chamar Pessoa.[/quote]
Discordo.
Pra mim é pura e simples questão de nomenclatura. A responsabilidade do objeto continua exatamente o mesmo, antes de DDD e alguns outros padrões utilizavamos DAO para isso, agora mudamos o nome para fazer a mesma coisa.
[/quote]
Rafael,

Nomes são importantes, não entendo porque você trata como algo irrelevante. Além de que DAO e Repository são conceitos distintos, isso já foi muito discutido aqui mesmo no GUJ.

Quanto a DAO ser um anti-pattern está ligado a sua utilização incorreta ao tentar abstratir um framework ORM como JPA/Hibernate. Não há esta necessidade para muitos casos, pois o JPA/Hibernate além de outras coisas atua como seu DAO.

Sim, um DAO pode ser uma implementação de um Repository. Não acho que sejam irrelevantes, mas não acredito que utilizar uma determinada nomenclatura torna a solução errada, se a responsabilidade é exatamente a mesma.

[quote=rponte]
Quanto a DAO ser um anti-pattern está ligado a sua utilização incorreta ao tentar abstratir um framework ORM como JPA/Hibernate. Não há esta necessidade para muitos casos, pois o JPA/Hibernate além de outras coisas atua como seu DAO.[/quote]
Essa é a parte principal que eu discordo, não vejo sentido em acoplar/tornar dependente minhas entidades/POJOs do mecanismo de persistência ou qualquer outro framework. Ao menos nunca passei em um cenário em que isso faria sentido.

[quote=Rafael Nunes]

[quote=rponte]
Quanto a DAO ser um anti-pattern está ligado a sua utilização incorreta ao tentar abstratir um framework ORM como JPA/Hibernate. Não há esta necessidade para muitos casos, pois o JPA/Hibernate além de outras coisas atua como seu DAO.[/quote]
Essa é a parte principal que eu discordo, não vejo sentido em acoplar/tornar dependente minhas entidades/POJOs do mecanismo de persistência ou qualquer outro framework. Ao menos nunca passei em um cenário em que isso faria sentido.[/quote]
Você sinceramente acha que tuas entidades e a forma como trabalha não estão ligadas/dependentes ao JPA/Hibernate?

De certa forma sim, mas não vejo sentido em criar mais dependência/acoplamento.

Se eu partir deste princípio, qual exatamente a diferença em eu transforma também esta entidade em um Managed Bean?

De certa forma sim, mas não vejo sentido em criar mais dependência/acoplamento.

Se eu partir deste princípio, qual exatamente a diferença em eu transforma também esta entidade em um Managed Bean?[/quote]

Você introduziu uma camada de indirecao, logo mais dependências.

[quote=Rafael Nunes]
Se eu partir deste princípio, qual exatamente a diferença em eu transforma também esta entidade em um Managed Bean?[/quote]

Do ponto de vista dele ser “Managed” nenhum. Ambos não possuem dependência com quem os gerencia. Aliás se suas entidades são dependentes de algum framework ORM você está fazendo errado. No exemplo anterior ColeçãoDePessoas não se encaixa na minha definição de entidade.

Não vejo problema nenhum em utilizar um DAO que utiliza hibernate na camada de persistência implementando o Repository (que fica no domain). Aliás, é uma implementação que utilizo frequentemente. Assim o mecanismo de persistencia (DAO) fica separado do domain, que encherga apenas o repository.

Essa “fobia” da palavra DAO não faz o menor sentido pra mim. E usar session (ou entitymanager, no caso de jpa) direto (sem um repository) na minha opinião é uma péssima idéia.

Não possui até eu precisar inserir um SelectItem, DataModel, etc, na entidade.

Esse foi o ponto que eu discordei do rpontes, não ter essa camada(que você deu um exemplo chamando de Colecao e eu chamando de DAO) que abstraia isso da minha entidade.

Isso é uma mentira tão grande e tão obvia que é impossivel que vc acreditasse nisso se vc entendesse o que está dizendo.
A todos vcs que - ainda - acham que DAO e Repositorio é a mesma coisas só tenho uma coisa a dizer : aprendam o que signfica Separação de responsabilidade.

Alguns pontos para começar:

  1. Se A é B , a reponsabilidade de A é , no minimo, a mesma de B.
  2. Se A implementa I , a responsabilidade de A é também a de I.

Se o DAO implementa o repositorio e o repositorio é um objeto do dominio, e como tal, tem responsabilidades do dominio, então o DAO também teria. Isso é um contrasenso porque o DAO não é um objeto do dominio!

Se isto não é claro como a água, leia de novo. Leia mais sobre responsabilidade e o Principio de Separação de Responsabilidade.
tá meio fraco…

O rei vai nu e só vcs não enxergam.

Isso é uma mentira tão grande e tão obvia que é impossivel que vc acreditasse nisso se vc entendesse o que está dizendo.
A todos vcs que - ainda - acham que DAO e Repositorio é a mesma coisas só tenho uma coisa a dizer : aprendam o que signfica Separação de responsabilidade.

Alguns pontos para começar:

  1. Se A é B , a reponsabilidade de A é , no minimo, a mesma de B.
  2. Se A implementa I , a responsabilidade de A é também a de I.

Se o DAO implementa o repositorio e o repositorio é um objeto do dominio, e como tal, tem responsabilidades do dominio, então o DAO também teria. Isso é um contrasenso porque o DAO não é um objeto do dominio!

Se isto não é claro como a água, leia de novo. Leia mais sobre responsabilidade e o Principio de Separação de Responsabilidade.
tá meio fraco…

O rei vai nu e só vcs não enxergam.

[/quote]
Primeiro: quando eu disse que DAO e Repository são a mesma coisa?? Nunca falei nada nem próximo disso.

Eu tenho na minha camada de domínio o repositório (interface). O resto do domínio conhece apenas o repositório, não faz idéia se ele é implementado usando hibernate, jpa, jdbc ou o que for. A única dependência, por exemplo, de um AlunoService é com o AlunoRepository. Tenho um AlunoDAO que implementa AlunoRepository e é injetado no service. Poderia chamar esta classe de HibernateAlunoRepository ou seja la o que for, ela é apenas uma implementação do repositório.

Outra coisa: não acho que você tem o mínimo de respeito pra discutir com alguém que nem conhece desta maneira. A partir deste posts, teu posts tão ignorados. Abraço.

Sergio, se você ler o capitulo sobre repository do livro DDD do Eric Evans, vai ver que Repository é basicamente para encapsular busca de dados:

Mas pra frente ele fala que é como uma coleção que reune todos os objetos do sistema, mas podemos dizer que na prática da na mesma… Pelo que o livro descreveu, bate com o propósito do DAO:

Não é exatamente a mesma coisa, mas tem basicamente a mesma responsabilidade. Isso não da para discutir…

Se você pegar os exemplo dos livro sobre repository, são muito parecidos com os exemplos de DAO que se vê por aí…