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

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:

[code]Classe Casa {

int codigoCasa;
String endereco;
int numero;

}[/code]

[code]Classe Pessoa {

int codigoPessoa;
String nome;
String endereco;
Date dtNascimento;
}[/code]

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

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.
}

[quote=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.

[code]
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.

}
[/code][/quote]
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! :slight_smile:

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.