Inner join com hibernate

Salvem,

Estou entre tapas e beijos com o Hibernate, e estou precisando saber ( de forma prática ) como fazer um inner join com ele.
A situação é a tipica relação Order -> LineItem , só que no meu caso o objeto de item tem uma PK composta do numero do item e o numero do pedido, assim :

Order                                LineItem
----------------                    ----------------
int numero (pk)                  ItemPK item_pk (pk)
int codigo_cliente                int codigo_produto

O mapping de LineItem :
<hibernate-mapping>
<class name="persistence.LineItem" table="TCSITE">
    <composite-id name="pk" class="persistence.ItemPK">
        <key-property name="numeroItem" column="NUMITEM" ype="int"/>
       <key-property name="numeroOS" column="NUMOS" type="int"/>
    </composite-id>
    <property name="codProduto" column="CODPROD" type="int"/>
</class>

</hibernate-mapping>

Quero executar uma query que me retorne LineItems filtrando pelo codigo_cliente do objeto Order. Em SQL (Oracle) eu faria assim :
SELECT * FROM LINEITEM ITE ORDER OS WHERE ITE.NUMOS = OS.NUMOS AND OS.CLIENTE = ?

Como fazer isto no Hibernate com o ambiente acima ??

me perdi um pouco com o seu exemplo, então vou postar um meu aqui.

Imagine uma tabela Pessoa e uma Veículo. Uma Pessoa pode ter vários veículos, então eu teria um “Set veiculos” em pessoa por exemplo.

na tabela veiculo tem um campo (codPessoa) que indica de quem este veículo é:

Em pessoa tem um one-to-many assim:

&lt;set name=&quot;veiculos&quot; &gt;
            &lt;key column=&quot;codProfessor&quot; /&gt;
            &lt;one-to-many class=&quot;hibernate.VeiculoVO&quot; /&gt;
&lt;/set&gt;

agora para fazer o join você faz assim:

select pessoa.nome,veiculo.nome from PessoaVO as pessoa inner join   pessoa.veiculos as veiculo

repare no “pessoa.veiculos” é o nome da collection que você definiu no mapping file.

espero ter ajudado

um abraço

qualquer coisa coloque o seu código mais detalhado,

to meio cansado hoje :slight_smile:

Ok,

 Agora imagine que Veiculo tem um campo chamado NumVeiculo que faz parte da PK juntamento com CodPessoa. Portanto temos uma composite-id e precisamos implementar uma classe de PK que chamaremos VeiculoPK. Logicamente essa classe tem dois campos, CodPessoa e NumVeiculo.
 Mas como montar o Veiculo.hbm.xml neste cenário, pois precisamos de um campo em Veiculo chamado CodPessoa, e no entanto este campo está dentro da classe de PK. Preciso "repetir" a informação ? assim :
     &lt;class name=&quot;Veiculo&quot; table=&quot;VEICULO&quot;&gt;
        &lt;composite-id name=&quot;pk&quot; class=&quot;VeiculoPK&quot;&gt;
            &lt;key-property name=&quot;CodPessoa&quot; type=&quot;int&quot;/&gt;
            &lt;key-property name=&quot;NumVeiculo&quot; type=&quot;int&quot;/&gt;
        &lt;composite-id/&gt;
        &lt;property name=&quot;CodPessoa&quot; type=&quot;int&quot; column=&quot;CODPESSOA&quot;/&gt;
      &lt;class/&gt;
 Sendo assim, a classe Veiculo seria assim &gt;
         public class Veiculo&#123;
               private VeiculoPK pk;
               private int CodPessoa;
               // outros campos , getters e setters...   
          &#125;
  É assim mesmo ou nào é nada disso ?
  Quando vc executa uma Query que lida com campos de objetos diferentes, como saber qual o tipo de objeto retornado pelo 

metodo list() ?

  Muito obrigado pela ajuda.[/code]

você não deve repetir a coluna, ao invés disso vc declara o relacionamento na própria composite key:
Então o VeiculoPK vai ser assim:

public class VeiculoPK
&#123; 
        private hibernate.model.PessoaVO pessoa;
        private int numVeiculo;
&#125; 
public class VeiculoVO
&#123; 
        private hibernate.model.VeiculoPK pk;
        private String nome;
        private java.util.Date ano;
&#125; 
&lt;class name=&quot;hibernate.model.PessoaVO&quot; table=&quot;Pessoa&quot;&gt;
		&lt;id name=&quot;id&quot; type=&quot;int&quot; column=&quot;id&quot;&gt;
			&lt;generator class=&quot;assigned&quot;/&gt;
		&lt;/id&gt;
		&lt;property name=&quot;nome&quot; column=&quot;nome&quot; type=&quot;string&quot;/&gt;
		&lt;property name=&quot;fone&quot; column=&quot;fone&quot; type=&quot;string&quot;/&gt;
		
		&lt;set name=&quot;veiculos&quot; cascade=&quot;all&quot;&gt;
            &lt;key column=&quot;codPessoa&quot; /&gt; 
            &lt;one-to-many class=&quot;hibernate.model.VeiculoVO&quot; /&gt; 
		&lt;/set&gt; 
	&lt;/class&gt;
&lt;class name=&quot;hibernate.model.VeiculoVO&quot; table=&quot;Veiculo&quot;&gt;
		&lt;composite-id name=&quot;pk&quot; class=&quot;hibernate.model.VeiculoPK&quot;&gt;
            &lt;key-many-to-one name=&quot;pessoa&quot; class=&quot;hibernate.model.PessoaVO&quot; column=&quot;codPessoa&quot;/&gt;
            &lt;key-property name=&quot;numVeiculo&quot; type=&quot;int&quot;/&gt;
        &lt;/composite-id&gt;
		&lt;property name=&quot;nome&quot; column=&quot;nome&quot; type=&quot;string&quot;/&gt;
		&lt;property name=&quot;ano&quot; column=&quot;ano&quot; type=&quot;date&quot;/&gt;
	&lt;/class&gt;

repare no “key-many-to-one”

agora como o relacionamento está na chave vc pode fazer:

PessoaVO pessoa = veiculo.getPk&#40;&#41;.getPessoa&#40;&#41;;

com relação ao find:

// Join entre aluno e carro
// isto retorna uma Lista de Object[2]

List list = session.find&#40;&quot;select p.nome,v.nome from PessoaVO as p inner join p.veiculos as v&quot;&#41;;

// vc pode criar um VO só para receber estes campos…
// para fazer deste jeito tem que ter um construtor no VO
// então isto retorna uma Lista de PessoaVeiculoVO

List list = session.find&#40;&quot;select new hibernate.PessoaVeiculoVO&#40;p.nome,v.nome&#41; from PessoaVO as p inner join p.veiculos as v&quot;&#41;;
public class PessoaVeiculoVO
&#123;
private String nomePessoa = null;
private String nomeVeiculo = null;

public PessoaVeiculoVO&#40;&#41;
	&#123;
	&#125;

public PessoaVeiculoVO&#40;String nomePessoa, String nomeVeiculo&#41;
	&#123;
		this.nomePessoa = nomePessoa;
		this.nomeVeiculo = nomeVeiculo;
	&#125;

// get/set

qualquer coisa estamos aí :slight_smile:

falow

Agora entendi. fiz um teste aqui e funcionou legal.
A única coisa que achei estranho ao analizar o SQL que o Hibernate gera é o seguinte :
Fiz uma Query partindo do “Veiculo”, e como na PK do Veiculo tem uma referencia à Pessoa ele executa o SELECT no Veiculo ,e ao processar o ResultSet ele executa outra SELECT na Pessoa para cada linha do ResultSet do Veiculo para carregar a tal referencia da PK.
Portanto se a SELECT do Veiculo retornar 10 linhas, ele vai no banco 10 vezes para trazer a Pessoa de cada Veiculo. Verifiquei também que se tiver alguma Pessoa com mais de um Veiculo ele vai no banco soh uma vez ( menos ruim ).
Será que consigo otimizar este tipo de coisa ?

esta também está sendo a minha preocupação…

mas quando vc definie um relacionamento tem a opção lazy=true para ele não trazer os relacionamentos automaticamente, isto é só buscaria veiculo ao fazer pessoa.getVeiculos()

tb estou com bastante dúvidas neste ponto do Hibernate.

O jeito então é quebrar cabeça para melhorar isso.
Vc sabe se existe alguma forma de simular o esquema de cache dos Entity Beans com commit-type A, ou seja , carrego uma referencia somente uma vez em todo o ciclo de vida da aplicação.
Isto é muito utilizado com tabelas (quase) nunca atualizadas, como cadastro de cidades, estados e similares.
Estou perguntando isso pois pelo que parece o ciclo de vida de uma referencia no Hibernate é o mesmo da Session, ou seja , uma transação. Isso é verdade ou entendi errado ?

você está certo. O correto é abrir apenas uma Session do Hibernate por transação…

se vc fizer o "load"de uma tabela e logo depois tentar fazer outro “load”,
o Hibernate lança seguinte erro:

“attempted to load into an instance that was already associated with the Session”

isto significa que vc somente pode carregar uma instancia de uma classe por Session do Hibernate, isto é por transação…

Entaum a única forma de se simular o COMMIT TYPE A dos EntityBeans e fazendo este controle na mão mesmo, pois eu poderia ter uma cache em um Singleton que seria populada somente uma vez ou em intervalos mais longos, fora do contexto de vida de um Session do Hibernate.