[RESOLVIDO]Count(*) do relacionamento @OneToMany

2 respostas
J

Olá pessoal do GUJ, estou com uma dúvida de como projetar na consulta do Hibernate a quantidades de 'filhos' de uma relação 1:N. Vamos as classes:

public class Grupo{

private String nome;

@Transient
private int tamanhoListaSubgrupos, tamanhoListaItens;

@OneToMany(mappedBy = "grupo", fetch = FetchType.LAZY)
private List<Subgrupo> subgrupos;
	
@OneToMany(mappedBy = "grupo", fetch = FetchType.LAZY)
private List<Item> itens;

// get e set ....
}

public class Item{

private String nome;

@ManyToOne @JoinColumn(name = "fk_grupo")
private Grupo grupo;

//get, set e outros atributos
}

public class Subgrupo{

private String nome;

@ManyToOne @JoinColumn(name = "fk_grupo")
private Grupo grupo;

//get, set e outros atributos
}
O problema começa quando eu tenho que listar os grupos, porque na view além de ser exibida as informações do Grupo, eu também tenho que exibir a quantidade de itens e subgruupos associados a ele. O select para isso é esse:
select g.id as id_grupo, g.nome as nome_grupo, 
      (select count(*) from subgrupos s where g.id = s.fk_grupo) as total_subgrupos, 
          (select count(*) from itens i where g.id = i.fk_grupo) as total_itens  
			from grupos g
Como estou usando o hibernate eu fiz desse jeito:
public List<Grupo> all() throws Exception {
		
		Criteria c = session.createCriteria(Grupo.class,"g")
		.setProjection(Projections.projectionList()
						.add(Projections.property("g.id").as("id") )
						.add(Projections.property("g.nome").as("nome") ) )
								
		.setResultTransformer(new AliasToBeanResultTransformer(Grupo.class) );
		
		List<Grupo> lista = c.list();
		for(Grupo g : lista){
			
			g.setTamanhoListaItens(getTotalItensGrupo(g.getId()));
			g.setTamanhoListaSubgrupos(getTotalSubgrupoGrupo(g.getId()));
		}
		return lista;	
}
Reparem que na primeira parte do método eu projeto os campos do Grupo, depois da lista gerada, eu a percorro e chamo os métodos
getTotalItensGrupo(long id)
e
getTotalSubgrupoGrupo(long id)
que retornam a quantidade de itens e subgrupos respectivamente associados ao Grupo. Tá funcionando perfeitamente, mas fica parecendo um POG :D . Minha pergunta é essa: como projetar diretamente com o Criteria o count(*) da relação @OneToMany?

Abraço a todos.

Jonh Paulo

2 Respostas

ivandasilva

Não testei mas, deve ser a mesma coisa que no SQL, você vai usar a projeção(funções de agregação) com os campos e depois você tem que fazer um group by…

Se não for assim, deve haver um jeito, porque fica gambiarresco mesmo…

J

Depois de muito procurar achei uma solução: a anotação @Formula do hibernate [url]http://gokhan.ozar.net/hibernate-derived-properties-formula-annotation/[/url]
Minhas classes ficaram assim:

public class Grupo {

	private String nome;
	
	@Formula("(select count(*) from subgrupos s where s.fk_grupo = id)")
	private int tamanhoListaSubgrupos; 
	
	@Formula("(select count(*) from itens i where i.fk_grupo = id)")
	private int tamanhoListaItens;

        //get e set
}

       // e o DAO
	public List<Grupo> all() throws Exception {
		
		Criteria c = session.createCriteria(Grupo.class,"g")
		.setProjection(Projections.projectionList()
						.add(Projections.property("g.id").as("id") )
						.add(Projections.property("g.nome").as("nome") )
						.add(Projections.property("g.tamanhoListaSubgrupos").as("tamanhoListaSubgrupos") )
						.add(Projections.property("g.tamanhoListaItens").as("tamanhoListaItens") ))
								
		.setResultTransformer(new AliasToBeanResultTransformer(Grupo.class) );
		
		return c.list();	
	}
Funcionou exatamente do jeito que eu queria. O SQL gerado foi esse aqui:
select  this_.id as y0_, this_.nome as y1_,
        (select  count(*) from subgrupos s where s.fk_grupo = this_.id) as y2_,
        (select  count(*) from itens i where i.fk_grupo = this_.id) as y3_ 
    from grupos this_

Abraços a todos

Jonh Paulo

Criado 3 de abril de 2013
Ultima resposta 5 de abr. de 2013
Respostas 2
Participantes 2