Repositórios trabalham com entidades, mas e se

… eu não poder/necessitar criar uma entidade para devolver ao serviço ?

Por exemplo, para retornar um produto pelo “id”, ele retornará ao serviço a entidade Produto. Mas e se eu apenas precisar retornar quantos itens foram encontrados (sim, eu uso DAO’s e sem ORM). A grosso modo, na DAO teriamos algo como:

Nesse caso, eu apenas receberia um inteiro contendo o total encontrado. Tendo isto em mente, teria sentido passar essa informação ao repositório ?
Na minha opinião, até faz sentido, porque a DAO é um mundo diferente do mundo do Domínio e suas entidades, mas por outro lado, seria apenas um “passa-repassa” entre DAO-Repositório-Serviço até chegar na Controladora/whatever-you-want o valor “10” por exemplo.

O que os senhores acham a respeito ?

Obs: poderia usar um SELECT * e retornar uma coleção de Produto, mas acho que isto iria gastar processamento desnecessário e ao meu ver, ficaria mais ‘feio’

Abraços!

Se é uma informação relevante para o negócio, deve estar no Repositório sim.

O ponto não é a complexidade da tarefa, mas sim seu objetivo.

[]'s

[quote=hlegius]… eu não poder/necessitar criar uma entidade para devolver ao serviço ?

Por exemplo, para retornar um produto pelo “id”, ele retornará ao serviço a entidade Produto. Mas e se eu apenas precisar retornar quantos itens foram encontrados (sim, eu uso DAO’s e sem ORM). A grosso modo, na DAO teriamos algo como:

Nesse caso, eu apenas receberia um inteiro contendo o total encontrado. Tendo isto em mente, teria sentido passar essa informação ao repositório ?
Na minha opinião, até faz sentido, porque a DAO é um mundo diferente do mundo do Domínio e suas entidades, mas por outro lado, seria apenas um “passa-repassa” entre DAO-Repositório-Serviço até chegar na Controladora/whatever-you-want o valor “10” por exemplo.

O que os senhores acham a respeito ?
[/quote]

A solução é simples embora, tlv, um pouco contra intuitiva.

O repositorio não retorna os objetos de dominio. Ele retorna o resultado da pesquisa. Esse resultado permite encontrar outras informações da pesquisa além dos dados em si.
É semelhante ao objeto ResultSet do JDBC. Vc não obtém objetos “linha” no jdbc.

Então , vc cria um interface Query com os seguintes métodos

[code]interface Query {

    public T find();
    public Collection<T> list();
    public int count();
    public boolean isEmpty();

}[/code]

Ai vc implementa como quiser. A implementação padrão é: list retorna a coleção com o resutado e contendo todos os objetos encontrados. find retorna só o primeiro ou null se a pesquisa é vazia. count retorna list().size()
e isEmpty retorna list().isEmpty();

Agora, para um repositorio que use JDBC vc pode implementar as coisas de forma diferente. count , por exemplo, executaria um select diferente que apenas retorna a contagem de itens sem ter que ler os itens ( é isso que vc quer). isEmpty pode executar o mesmo select e comparar se é zero. find pode limitar a procurar ao primeiro item como um Top 1 (SQL SErver ) ou limit (postgres e outros…)

Enfim, com esta interface vc pode escolher como executar o sql porque sabe qual seria mais eficiente.

Outra vantagem do Query é que para repetir a query vc não precisa do repositorio. vc simplesmente invoca o método do query de novo. Se existirem dados novos, eles viram no resultado. Isto é prático especialmente se vc adicionar mais um método list(start, count) que retorna os count seguintes itens a partir de start. Isto é util para paginação.

Se ele retorna os resultados da pesquisa, é correto retornar por ele um “inteiro” contendo o valor da pesquisa do count() correto ?

Entendi. Estive reparando que o Repository serve para buscar dados, trazer list/Collections … não é necessariamente tarefa dele as outras coisas, como adicionar, atualizar, remover ou até mesmo, trazer um valor inteiro - o count().
Então, essa Query object se parece meio com o Repository no aspécto do list()… ou seja, fiquei meio perdido com isto. Um se comunica com o outro, ou cada um faz um papel diferente e nem se encontram no sistema ?

Procurei um pouco sobre QueryObject, mas não descobri se ele é do lado da infra ou se é pertencente ao domínio… acho que meu cerebro deu um nó =)
Ao que reparei, o pessoal usa junto a Criteria que tudo isso junto acaba sendo o embrião de um ORM tipo hibernate…

Se eu falei só besteira, realmente é porque o nó está bem atado =(

Ok, os nomes não ajudaram. QueryObject é um padrão para vc passar os parâmetros para o Repositorio. É o input da pesquisa.
O objeto que me referi é o output da pesquisa o resultado. Não sei se existe um padrão para isto, mas se existisse seria algo como ResultObject.

Um repositorio ideal ( no sentido de ser proximo da ideia ) teria vários métodos de pesquisa, cada um recebendo um objeto com os parametros da pesquisa e retornando um objeto de resultado. (Como exemplo, pense no statement do SQL. Ele recebe um String como parametro e retorna um ResultSet como resposta).

O respositorio realmente devolve uma lista com os objetos que encontrou, mas isso não significa que os métodos retornem List.
Quando vc usa List , List é o seu ResultObject. Repare que vc pode usar a interface de List para implementar as mesma coisa que eu falei que poderia com Query. Afinal List tem métodos para saber o tamanho (size) , se é vazio ( isEmpty) etc… Mas List tem um conjunto de outros métodos que não são relevantes como retainAll e removeAll. Enfim, vc pode implementar uma classe que implementa List e utiliza SQL diferente para implementar cada parte. Mas vc tem pouca flexibilidade.

Do ponto de vista do design é mais correto ter um objeto especifico para ser o seu ResultObject. Este objeto terá uma interface mais simples que List e portanto vai libertá-lo de ter de implementar métodos exotiericos como retainAll().

Mesmo assim, esse objeto terá que permitir acesso aos objetos que são o resultado da pesquisa. Por isso ele tem um método que retorna um collection. Mas o programador pode invocar outros métodos mais uteis e mais eficiente como count();

Ou seja, invocar resultObject.count() é mais rápido que invocar resultObject.list().size() porque por detrás dos panos vc não está carregando nenhum objeto realmente.

Aqui chegamos na questão da implementação. Como seu design segue SoC e o objeto de retorno é uma interface, vc pode simplesmente implementá-lo de várias formas conforme for mais util. O seu conhecimento do backend pode ser utilizado para aumentar a eficiencia e portanto a velocidade e diminuir o consumo de memória.

Vc pode usar vários padrões agora porque o objeto que vc retorna apenas tem que implementar uma interface simples.
(Flyheight e Fastlane são exemplos)

Se vc apenas carrega um List e devolve vc ainda posa fazer isso com o obecjto de retorno.
Por exemplo ( e chamando de QueryResult o objeto que chamei antes de Query para não confundir)

[code]public class Repositorio {

public QueryResult findActive(){
List todosActivos = // … executa o query que retorna um list com o resultado

      return new ListQueryResult(todosActivos);

}
}

public class ListQueryResult implements QueryResult{

List all;

ListQueryResult (List all){
this.all = all;
}

public T find (){
return all.isempty ? null : all.get(0);
}

public Collection list(){
return Collections.unmodifiableCollection(all);
}

public int count (){
return all.size();
}

public boolean isEmpty (){
return all.isEmpty();
}

}[/code]

Mas vc poderia implementar assim :

[code]public class Repositorio {

public QueryResult findActive(){

    // não executa nada
      return new SQLQueryResult (datasource);

}
}

public class SQLQueryResult implements QueryResult{

DataSource datasource;

ListQueryResult (DataSource datasource{
this.datasource = datasource;
}

public T find (){

     ResultSet rs = execute("SELECT TOP 1  * FROM table ... ");

       if (rs.next){
           return readObject(rs);
      } else {
           return null;
      }

}

public Collection list(){

     ResultSet rs = execute("SELECT * FROM table ... ");

     List all = new ArrayList();

      while (rs.next){
           all.add(readObject(rs));
      } 
    return Collections.unmodifiableCollection(all);

}

public int count (){
ResultSet rs = execute("SELECT count(1) FROM table … ");

     rs.next
          
  return rs.getInt(1);

}

public boolean isEmpty (){
return this.count() == 0;
}

}[/code]

O codigo de invocação do SQL é apenas um exemplo. Vc teria que tratar exceptions, fechar connections , etc…
O DataSource é para obter a coneção (datasource.getConnection():wink:

A ideia é que cada método faz o seu proprio SQL ligeiramente diferente e otimizado para aumentar a eficiencia.

Neste caso, o Repositório “ideal” teria várias pesquisas especializadas. Cada tipo de pesquisa receberia um QueryObject como parametro para podermos filtrar a informação a ser buscada igual você exemplificou, correto ?
Ou seja:

Ah sim, perfeito. Entendi seu ponto de vista. Implementar algo mais “direto” à implementar algo que me obriga a implementar comportamentos que eu não vou ultilizar.

Aqui é o ponto da dúvida. Meu Repository pode muito bem retornar ao meu Serviço um valor “não-collection/list”. Posso muito bem no meu serviço solicitar ao meu repositório que retorne-me o total encontrado, como por exemplo:

public void verificaTotal() { int totalFound = this.repositorio.count(queryObject); }

Isso seria equivalente a eu chamar o find().size() só que economizando uma boa memória, pois por detrás teriamos apenas um SELECT COUNT(1)/TOP 1…

Legal, acho que isso desata o nó que esse tópico tinha dado em minha cabeça ! Fico muito grato pela explicação completa que deu.

Agora, aqui você comentou sobre a QueryObject. Eu durante esse final de semana consultei alguns livros e li algumas coisas na rede sobre. Ao que pude entender, o QueryObject é o cara que “tira uma DAO” de jogo. Ele quem roda os SQL’s e devolve os resultados ao Repositório. Ele trabalha junto ao Criteria que é o cara responsável por criar os critérios de busca.

No exemplo que vi no livro, o Repositório do cara recebia uma Criteria como parametro e o Repositório implementava o QueryObject passando a entidade e a criteria por meio de setter injection.
A QueryObject dele montava a sentença SQL, buscava os dados e retornava o ResultSet ao repositório que montava a collection e devolvia assim ao serviço.

O Repositório dele se comporta de maneira bem similar ao que você explicou aqui na thread. Um list simples e “descompromissado” com métodos que não têm utilidade e o count() dele retorna o integer usando o TOP do SQL.
Tal implementação estaria correta ?

Agradeço a força !

Abraço!

Neste caso, o Repositório “ideal” teria várias pesquisas especializadas. Cada tipo de pesquisa receberia um QueryObject como parametro para podermos filtrar a informação a ser buscada igual você exemplificou, correto ?
Ou seja:

[/quote]

Ah! agora entendi o seu ponto. Vc acha que isso são pesquisas especializadas.
Não. São 3 métodos fazendo a mesma pesquisa e retornando informações diferentes dela.

Em um projeto onde vc tivesse a pesquisa “usuáriosAtivos” vc teria

findUsuariosAtivos : List
getFirstusuarioAtivo : usuario
countUsuariosAtivos : int

Para cada pesquisa vc teria 3 metodos. Para N pesqusias vc teria 3N métodos.
Com o outro modelo vc agrupa os métodos em um objeto de retorno. Então vc tem N pesquisas e N métodos.
muito mais simples , não ?

Repare que a frase SQL é a mesma ( porque a pesquisa é a mesma) apenas tem alguns parametros diferentes.
Se vc tiver 3 metodos vc vai escrever a pesquisa 3 vezes. quando a pesquisa mudar é provável que vc esqueça de mudar nos outros 2 métodos. Esse é o real problema da sua opção : manutenabilidade.

For que, vc fizer do seu jeito o seu repositorio vira um DAO. Acho que não isso que vc quer.

Não. Nada disso.
O QueryObject não faz nada. Ele é apenas um conjunto de dados. Um criteria do hibernate é um QueryObject.
O String SQL passado no statement é um QueryObject.

Em um repositorio os parametros são normalmente simples findByID(Integer id) , findByName(String name) , findActive() , findSelledIn (Date start, Date end), etc… quando vc tem muitos parametros vc vai querer combiná-lo num so objeto por exemplo
findSelledIn(Interval intervalo) seria equiavalente ao anterior mas com o start e o end dentro do obejto intervalo, que aqui é o seu QueryObject.

Agora, o QueryObject tende a ser mais complexo. A ideia é vc poder pedir aquelas 4 informações de forma combinada algo assim

QueryObject q = QueryObject.for(Product.class).
where("name").eq(name).
and("active").isTrue().
and("selled").in(intervalo)

Ai vc passa para o método find() e pronto. Bácisamente o seu repositorio começa a ter um só método. Só que isso destroi o repositorio. O objectivo do repositorio é manter e conter a contrução do QueryObject se vc já o opassa construido quer dizer que outro objeto o contruiu - que não o repositorio - e portanto está violando o papel do repositorio. O repositorio torna-se um DAO.

O DAO e o DomainStore funcionam bem com QueryObject. Repare como o QueryObject e SQL são bem semelhantes.
O repositorio recebe parametros mais simples, cria o QueryObject mais complexo que o DAO ou o DomainStore entende e o passa a ele. Depois recebe o resultado e trata esse resultado para ser retornado na estrutura certa.

aposto que isso não era um repositorio e sim um DAO. Pela simples razão que os repositorios não recebem QueryObject complexos ( como já expliquei ) e Criteria é um objeto complexo.
Isso que vc descreveu é o que o um DAO ou um DomainStore faria.

Para um DAO sim. Para um Repositorio não.
A Criteria que foi enviado ao objeto veio de onde ? Foi montada por quem ? Quem escolheu os parametros para ela ?
Em um sistema como Repositorio , seria o repositorios a fazer isso e a invocar esse objeto que vc descreveu.
em um sistema sem Repositorio , básicamente qualquer classe pode invocar o DAO, logo a construção do Criteria está espalhada pelo sistema inteiro. E isso é um problema. Esse é o problema que o repositorio tenta resolver. ele é um cara “acima” do DAO que sabe como criar Criterias , invocar o DAO, e tratar o resultado.

Cuidado com isso. Segundo Evans:

Um Repositório é uma ilusão de coleção de objetos, não alguém que responde à queries. Se você quer saber quantos objetos estão dentro de um repositório provavelmente para o cliente isto é apenas um atributo deste, não o resultado de uma pesquisa.

E antes de partir para QueryObject, algo bem inra-estrutura e fora de DDD, siga a suestão do Evans e faça a dobradinha Specificaction/Repository:

Agora se você ainda não leu o livro eu recomendo que o faça antes de tentar qualquer coisa com Domain-Driven Design. Existem muitas fontes de informação completamente distorcidas por aí.

[quote=“sergiotaborda”]Ah! agora entendi o seu ponto. Vc acha que isso são pesquisas especializadas.
Não. São 3 métodos fazendo a mesma pesquisa e retornando informações diferentes dela.

Em um projeto onde vc tivesse a pesquisa “usuáriosAtivos” vc teria

findUsuariosAtivos : List
getFirstusuarioAtivo : usuario
countUsuariosAtivos : int

Para cada pesquisa vc teria 3 metodos. Para N pesqusias vc teria 3N métodos.
Com o outro modelo vc agrupa os métodos em um objeto de retorno. Então vc tem N pesquisas e N métodos.
muito mais simples , não ?[/quote]

Pera lá então: no seu exemplo temos somente 1 tipo de busca. O que varia são os tipos de retorno. Um Retorna a Collection outro a entidade fora da collection e o outro um número (inteiro) possívelmente.
3 métodos, 1 tipo de busca.
Com isto realmente teriamos muito código duplicado e o problema da manutenabilidade como você disse. Porém, o “outro modelo” que você citou eu não entendi bem como poderia especificar ao método do Repositório que eu quero um getFirstusuarioAtivo ou que eu quero um countUsuariosAtivos.

[quote][code]public class Repositorio {

public QueryResult findActive(){

    // não executa nada
      return new SQLQueryResult (datasource);

}
}

public class SQLQueryResult implements QueryResult{

DataSource datasource;

ListQueryResult (DataSource datasource{
this.datasource = datasource;
}

public T find (){

     ResultSet rs = execute("SELECT TOP 1  * FROM table ... ");

       if (rs.next){
           return readObject(rs);
      } else {
           return null;
      }

}

public Collection list(){

     ResultSet rs = execute("SELECT * FROM table ... ");

     List all = new ArrayList();

      while (rs.next){
           all.add(readObject(rs));
      } 
    return Collections.unmodifiableCollection(all);

}

public int count (){
ResultSet rs = execute("SELECT count(1) FROM table … ");

     rs.next
          
  return rs.getInt(1);

}

public boolean isEmpty (){
return this.count() == 0;
}

}[/code][/quote]
Veja, no seu exemplo eu usaria o que para dizer ao findActive() que eu quero chamar o find() que me retornará um TOP 1 por exemplo ?

[quote=“sergiotaborda”]Não. Nada disso.
O QueryObject não faz nada. Ele é apenas um conjunto de dados. Um criteria do hibernate é um QueryObject.
O String SQL passado no statement é um QueryObject.[/quote]

Legal, até aqui eu entendi. No meu pensamento o QueryObject mandava a DAO passear, mas depois da sua explicação eu percebi que ele manda o Repositório passear.
Ao que entendi, o Repositório está para nos servir com Objetos da persistência e agora também evitar um monte de Criteria espalhadas pelas Actions.

Se eu entendi corretamente, uma implementação possível seria:

[code]public class Repositorio {

 public Result findAtivos(int porCep) {
       // monta a o critério/query object
       // passa ao criteria a espeficicação de que queremos por cep
       ResultSet rs = usuariosDao.find(Criteria);
       // monta o list/collection ou transmite uma info de não localizada
 }

}[/code]

Minha Action chamaria o Repositório - nesse caso acho que não precisaria de Serviço:

[code]
public class AlgumacoisaAction {

public static void main(String..) {
    Repositorio repo = new Repositorio;
    int cep = 12345678;
    repo.findAtivos(cep);
}

}[/code]

Dessa forma eu não exibiria a implementação dos critérios de busca, evitaria um monte de Criterio nas Actions.
Eu apenas não entendi como poderia fazer meu Repositório buscar de formas diferentes uma mesma informação, assumindo o exemplo acima…

[code]public class Repositorio {

 public Result findAtivos(int porCep) {
       // monta a o critério/query object
       // passa ao criteria a espeficicação de que queremos por cep
       ResultSet rs = usuariosDao.find(Criteria);
       // monta o list/collection ou transmite uma info de não localizada
 }

 public int countAtivos(int porCep) {
     //monta o critério
     // passa ao critéria o cep
     int rs = usuariosDao.count(Criteria);
     // retorna isto
 }

}[/code]

[code]
public class AlgumacoisaAction {

public static void main(String..) {
    Repositorio repo = new Repositorio;
    int cep = 12345678;
    repo.findAtivos(cep);
    int totalAtivoPorCep = repo.countAtivos(cep);
}

}[/code]

Ao que entendi, minha DAO é melhor aproveitada, porém eu teria 3n Métodos no Repositório para n pesquisas especializadas. Justamente o que não é ideal para a manutenabilidade. =(
Pois se eu precisasse fazer uma busca por inativos, eu teria que adicionar no repositório mais 3 métodos. findInativos(); listInativos(); countInativos(); A DAO ficaria com os 3 de sempre, penso.

[quote=“sergiotaborda”]Agora, o QueryObject tende a ser mais complexo. A ideia é vc poder pedir aquelas 4 informações de forma combinada algo assim
QueryObject q = QueryObject.for(Product.class). where(“name”).eq(name). and(“active”).isTrue(). and(“selled”).in(intervalo)

Ai vc passa para o método find() e pronto. Bácisamente o seu repositorio começa a ter um só método. Só que isso destroi o repositorio. O objectivo do repositorio é manter e conter a contrução do QueryObject[/quote]

Entendi. A idéia do QueryObject é não ter aquela chuva de pesquisa no Repositório, logo, isso acaba com a utilidade do mesmo. Entretanto, teremos QueryObject esparramadas em todas Actions. Se precisar alterar algo algum dia, ferrou ! Mas vem cá, o hibernate não trabalha exatamente assim ?

[quote=“sergiotaborda”]aposto que isso não era um repositorio e sim um DAO. Pela simples razão que os repositorios não recebem QueryObject complexos ( como já expliquei ) e Criteria é um objeto complexo.
Isso que vc descreveu é o que o um DAO ou um DomainStore faria. [/quote]

Sim, era um repositório! Veja na imagem: http://helio.hlegius.pro.br/imagens/oop/repository_de_acordo_com_livro.jpg

Veio da Action.

Pela Action.

Possivelmente poderia ter sido o usuário utilizando-se da interface selecionou os campos a serem filtrados, porém, novamente a Action que tratou essa informação e criou a criteria.

[quote=“sergiotaborda”]Em um sistema como Repositorio , seria o repositorios a fazer isso e a invocar esse objeto que vc descreveu.
em um sistema sem Repositorio , básicamente qualquer classe pode invocar o DAO, logo a construção do Criteria está espalhada pelo sistema inteiro. E isso é um problema. Esse é o problema que o repositorio tenta resolver. ele é um cara “acima” do DAO que sabe como criar Criterias , invocar o DAO, e tratar o resultado. [/quote]
Isso reforça a idéia: repositório ajuda na manutenção das instruções da Dao.

Isso ! No caso, aliás, no meu caso, geralmente eu preciso de um “count()” para retornar informações para paginações ou/e exibir informações adicionais na interface, como por exemplo: “Vendo X registros de um total de 400”. Em ambos casos, eu precisaria fazer um find() especializado naquele filtro + um count() para saber quantos são os registros todos (sem filtros).

Neste caso Phillip, o que poderia eu fazer ? Implementar o count() no repositório retornando um “Int” ao que entendi, você não é muito a favor, mas eu ainda não consigo ver outra solução…

Seguirei sem dúvidas. Até por que, se eu for criar um queryobject e suas criterias é melhor eu usar algo pronto, como hibernate…

Farei assim que possível. A grande questão é que apenas fora do país tem esse livro disponível, e as lojas nacionais têm um prazo altíssimo para “possível” entrega do mesmo. Isso quebra as pernas =(

[quote=hlegius][quote=“sergiotaborda”]
Para cada pesquisa vc teria 3 metodos. Para N pesqusias vc teria 3N métodos.
Com o outro modelo vc agrupa os métodos em um objeto de retorno. Então vc tem N pesquisas e N métodos.
muito mais simples , não ?[/quote]

Pera lá então: no seu exemplo temos somente 1 tipo de busca. O que varia são os tipos de retorno. Um Retorna a Collection outro a entidade fora da collection e o outro um número (inteiro) possívelmente.
3 métodos, 1 tipo de busca.
Com isto realmente teriamos muito código duplicado e o problema da manutenabilidade como você disse. Porém, o “outro modelo” que você citou eu não entendi bem como poderia especificar ao método do Repositório que eu quero um getFirstusuarioAtivo ou que eu quero um countUsuariosAtivos.
[/quote]

Assim :


QueryResult result = repositorio.findActive();

result.count() // quantos são 
result.find() // o primeiro encontrado
result.list() // todos os encontrados 
result.isEmpty() // encontrou algum ?

if (result.count()>0){  // ou !result.isEmpty()

   for (Produto p : result.list()){
             print(p.getName());
   }

}

repare que result.count() é mais eficiente que fazer o select todo
vc só irá fazer o select em list() se souber que ha alguma coisa para ler. ( isto é um exemplo, no codigo real vc faz o for e pronto)

Outra forma de usar


// todos os produtos
Collection produtos = repositorio.findAll().list();

// quantos produtos 

int quantos = repositorio.findAll().count(); 

// Todos os produtos ativos

Collection produtos = repositorio.findActive().list();

// quantos produtos foram vendidos o mes passado ? 

Month month = Month.current().previous(); // objeto de exemplo só para que se entenda
int quantosVendidos = repositorio.findSelled( month.start(), month.end() ).count();

Repare que um campo só no repositorio não serve. repositorio.count() contao quê ? Isso no máximo informaria o numero total de produtos no repositório mas não o informaria, por exemplo, quantos são ativos ( ou inativos , ou de um certo cliente, ou de uma certa data, etc…). Vc precisa de um count para cada pesquisa. Isso permite automatizar coisas como paginação, por exemplo.

Exactamente isso.

ficaria assim

[code]
public class AlgumacoisaAction {

public static void main(String..) {
    Repositorio repo = new Repositorio;
    int cep = 12345678;
     int totalAtivoPorCep = repo.findAtivos(cep).count();
}

}[/code]

ou

[code]
public class AlgumacoisaAction {

public static void main(String..) {
    Repositorio repo = new Repositorio;
    int cep = 12345678;
     QueryResult qr = repo.findAtivos(cep);
     int totalAtivoPorCep = qr.count();
}

}[/code]

O Hibernate funciona exactamente assim porque é uma implementação de DomainStore. Usar QueryObject com DomainStore ou DAO é natural.
Mas isso não significa que vc tem que espalhar as suas Criteria pelos seus Actions. Isso o hibernate não o obriga a fazer.
Vc pode criar um repositorio que chama o hibernate tranqüilamente. (aliás vc deve fazer isso se gosta de codigo mantenivel )

O repositorio que use hibernate é responsável por montar os criteria com base nos parametros e passar ao hibernate.
Implementar um QueryResult baseado no query do hibernate tb é simples, já que o Criteria já implementa os vários métodos diferentes ( ele já otimiza as chamadas da forma que estavamos falando).

Exatamente. esse é o papel principal do repositório. Ele tem outras vantagens, mas todas derivam dai.

Só uma ultima coisa : Repositorios podem - devem - ser usados sempre que vc tiver que escrever pesquisas . Seja SQL puro, Hibernate, JPA , sei la… e em nada usa um repositorio significa que vc esteja utilizando a filosofia DDD ou qualquer uma das suas práticas, vc está simplesmente seguindo o Principio de Separação de Responsabildiade, em particular Encapsulamento, que é uma prática comum do OO.

[quote=sergiotaborda][quote=hlegius]


QueryResult result = repositorio.findActive();

result.count() // quantos são 
result.find() // o primeiro encontrado
result.list() // todos os encontrados 
result.isEmpty() // encontrou algum ?

if (result.count()>0){  // ou !result.isEmpty()

   for (Produto p : result.list()){
             print(p.getName());
   }

}

repare que result.count() é mais eficiente que fazer o select todo
vc só irá fazer o select em list() se souber que ha alguma coisa para ler. ( isto é um exemplo, no codigo real vc faz o for e pronto)

Outra forma de usar


// todos os produtos
Collection produtos = repositorio.findAll().list();

// quantos produtos 

int quantos = repositorio.findAll().count(); 

// Todos os produtos ativos

Collection produtos = repositorio.findActive().list();

// quantos produtos foram vendidos o mes passado ? 

Month month = Month.current().previous(); // objeto de exemplo só para que se entenda
int quantosVendidos = repositorio.findSelled( month.start(), month.end() ).count();

[/quote][/quote]

Ao que entendi, esse findActive() não iria fazer chamada alguma na SQLDao. Apenas montaria o critério de busca. Daí, com o critério pronto, o list() retornaria todos, o count() o SELECT COUNT, o isEmpty() verificaria se não retornou nada e etc… correto ou entendi errado ?

[quote=“sergiotaborda”]O Hibernate funciona exactamente assim porque é uma implementação de DomainStore. Usar QueryObject com DomainStore ou DAO é natural.
Mas isso não significa que vc tem que espalhar as suas Criteria pelos seus Actions. Isso o hibernate não o obriga a fazer.
Vc pode criar um repositorio que chama o hibernate tranqüilamente. (aliás vc deve fazer isso se gosta de codigo mantenivel )

O repositorio que use hibernate é responsável por montar os criteria com base nos parametros e passar ao hibernate.
Implementar um QueryResult baseado no query do hibernate tb é simples, já que o Criteria já implementa os vários métodos diferentes ( ele já otimiza as chamadas da forma que estavamos falando). [/quote]

Legal. Muitos exemplos que eu vi pela rede, trabalha com Active Records. A implementação com Repositório no caso, seria bem similar a implementação com DAO’s comuns, né ? Digo, apenas precisaria mudar, onde eu chamo as daos, eu precisaria transportar os dados para o Hibernate.

Ufa! Acho que estou começando a sacar a idéia =)

O que por si só é excelente. :smiley:

Abraço e obrigado pela força! Realmente ajudou muito !

Correto. Ele prepara o Criteria , cria um QueryResult para esse critério e retorna.
Internamente o QueryResult utiliza o critério para fazer a pesquisa. Ele pode alterar o critério “ligeiramente” para invocar o resultado que ele quer ( por exemplo o find poderia adicionar o comando criteria.setRange(1,1) ( trás só 1, começando no primeiro) - isso vai se tornar um TOP 1, ou um Limit 1 offset 1 no banco)

Objetos que encapsulam chamadas ao Hibernate e encapsulam a criação de critérios são na realidade Repositorios. É que existe essa moda de os chamar de DAO, mas na realiade DAO é outra coisa. Mas , sim, onde vc tem dao chamando o hibernate vc teria repositorios chamando o hibernate