[RESOLVIDO] Hibernate - Dúvida HQL inner join em tabelas independentes

3 respostas
D

Prezados,

estou com uma dúvida referente a HQL do hibernate.
Estou tentando fazer uma consulta razoavelmente simples.
Possuo minhas classes mapeadas e tudo configurado normalmente.

Minha consulta consiste um select com um inner join de duas tabelas onde as mesmas não possuem referências de uma para outra.
Exemplo:

Classe Casa {

   int codigoCasa;
   String endereco;
   int numero;

}
Classe Pessoa {

   int codigoPessoa;
   String nome;
   String endereco;
   Date dtNascimento;
}
Levando em consideração que as classes estão mapeadas corretamente, executei o seguinte HQL:
Select p.codigoPessoa, p.nome, c.codigoCasa, c.numero 
  from Casa c 
  inner join
  Pessoa p 
  where c.endereco = p.endereco

Retornou o seguinte erro: javax.servlet.ServletException: Path expected for join!

Tentei executar consulta abaixo, mas nem faz sentido, gerando o erro que eu já imaginava: "javax.servlet.ServletException: could not resolve property: ", pois não existem referências entre uma classe e outra:

Select p.codigoPessoa, p.nome, p.endereco, c.codigoCasa, c.numero 
  from Casa c 
  inner join
  m.pessoa p 
  where c.endereco = p.endereco

Ao executar a Query

Select p.codigoPessoa, p.nome, p.endereco, c.codigoCasa, c.numero 
  from Casa c, Pessoa p 
  where c.endereco = p.endereco
no "Query query = sessao.createQuery()" passando a consulta a cima foi executado com sucesso, porém, na instrução: query.list() uma lista é retornada, mas impossível e pegar os atributos, pois eles não possuem nomes, somente o valor conforme estrutura do "ctrl+shift+i do eclipse" abaixo:
"query.list()" = ArrayList<E> (id=203)
	elementData = Object[5] (id=205)
		[0]=Object[4] (id=207)
			[0] int (id=207)
			[1] "Paulo" (id=207)
			[2] int (id=217)
			[3] int (id=218)
		[1]=Object[4] (id=220)
		[2]=Object[4] (id=222)
		[3]=Object[4] (id=224)
		[4]=Object[4] (id=226)

Na parte "int (id=###)" quando seleciono no ctrl+shift+i, aparece o valor correto do select

Não postei a minha classe real pois elas são grandes, criei essas duas agora, mas elas já expressam a minha dúvida.

Obrigado

3 Respostas

R

O último select é o correto.

Porém, ele sempre vai retornar dessa forma, pois o Hibernate não sabe que objeto é esse que você quer.

Então você pode transformar esses Object[] em uma classe que tenha nome.

Algo assim:

Set&lt;MinhaClasse&gt; transformados = new HashSet&lt;MinhaClasse&gt;();
	Iterator&lt;Object[]&gt; iterate = session.createQuery(hql).iterate();

	while (iterate.hasNext()) {
		Object[] next = iterate.next();
		transformados.add(new MinhaClasse(next));
	}

	return transformados;

Já o MinhaClasse tem um construtor que sabe o que fazer com esse array de object provindo DESSE hql apenas.

class MinhaClasse {
	private final Integer codigoPessoa;
	private final String nome;
	private final String endereco;
	private final Integer codigoCasa;
	private final Integer numero;

	public MinhaClasse(Object[] o) {
		int ix = 0;

		codigoPessoa = Integer.parseInt(String.valueOf(o[ix++]));
		nome = String.valueOf(o[ix++]);
		endereco = String.valueOf(o[ix++]);
		codigoCasa = Integer.parseInt(String.valueOf(o[ix++]));
		numero = Integer.parseInt(String.valueOf(o[ix++]));
	}

	// Getters apenas, pois você não precisa de setters.
}
D
Rafael Guerreiro:
O último select é o correto.

Porém, ele sempre vai retornar dessa forma, pois o Hibernate não sabe que objeto é esse que você quer.

Então você pode transformar esses Object[] em uma classe que tenha nome.

Algo assim:
Set&lt;MinhaClasse&gt; transformados = new HashSet&lt;MinhaClasse&gt;();
	Iterator&lt;Object[]&gt; iterate = session.createQuery(hql).iterate();

	while (iterate.hasNext()) {
		Object[] next = iterate.next();
		transformados.add(new MinhaClasse(next));
	}

	return transformados;
Já o MinhaClasse tem um construtor que sabe o que fazer com esse array de object provindo DESSE hql apenas.
class MinhaClasse {
	private final Integer codigoPessoa;
	private final String nome;
	private final String endereco;
	private final Integer codigoCasa;
	private final Integer numero;

	public MinhaClasse(Object[] o) {
		int ix = 0;

		codigoPessoa = Integer.parseInt(String.valueOf(o[ix++]));
		nome = String.valueOf(o[ix++]);
		endereco = String.valueOf(o[ix++]);
		codigoCasa = Integer.parseInt(String.valueOf(o[ix++]));
		numero = Integer.parseInt(String.valueOf(o[ix++]));
	}

	// Getters apenas, pois você não precisa de setters.
}
Perfeito!

Resolvido!

Alterei meu código para essa estrutura. Muito obrigado!

A única coisa que mudei foi o
Set&lt;MinhaClasse&gt; transformados = new HashSet&lt;MinhaClasse&gt;();
para
List&lt;MinhaClasse&gt; transformados = new ArrayList&lt;MinhaClasse&gt;();
pq eu precisava de uma lista e não conheço direito a estrutura do "Set<E>". Mas vou pesquisar!

Vlw mesmo! :)

R

O Set garante que você não tenha nenhum objeto duplicado. Desde que você implemente corretamente o hashCode() e o equals().

Pesquise sobre como eles devem ser implementados. O eclipse te ajuda a fazer isso, mas ainda assim, é interessante saber COMO.

Além disso, ele é muito mais rápido para encontrar algum registro na sua coleção, por isso, incluir MUITOS registros nele é bem mais rápido que em um List.

Infelizmente, toda essa maravilha vem com 2 problemas correlacionados:

  1. Você não pode garantir a ordem de um set, um determinado registro pode entrar no “começo” ou no “meio” dele.
  2. Como você não consegue garantir a ordem, não é possível achar um registro pelo index dele.

Mas lembre-se, o set só vai funcionar direito se você implementar hashCode() e equals() corretamente.

Criado 30 de outubro de 2014
Ultima resposta 31 de out. de 2014
Respostas 3
Participantes 2