hibernateXcompositeID

25 respostas
M

Em uma tabela, tenho um campo que é chave, e que é da própria tabela, e um outro campo q é chave mas que é foreing key.Os dois formam minha chave composta. Quando eu deixo o campo que é foreing key no mapeamento como apenas <key-property> ele dá certo. Mas eu acho q o correto mesmo seria se ele fosse <key-many-to-one>, já que ele se refere a um campo de outra tabela. Mas quando eu mudo pra este tipo não dá certo…
O que pode estar acontecendo? Qual a forma correta de se usar <key-many-to-one>…os .java e hbm ???
AH e eu nao estou usando annotations e nem o plugin do eclipse…por favor…se puderem me dar exemplos sem os “arrobas”…rs

25 Respostas

J

Não seria algo assim?

&lt;composite-id&gt; &lt;key-property name=&quot;chave&quot; column=&quot;chave&quot; /&gt; &lt;key-many-to-one name=&quot;estrangeira&quot; class=&quot;ClasseEstrangeira&quot; column=&quot;estrangeira&quot;/&gt; &lt;/composite-id&gt;

Assim não funciona? Qual o erro?

M

Assim mesmo que eu estou fazendo.
Será algum erro na implementação da ClasseEstrangeira? Você poderia me dar um exemplo de como fica a ClasseEstrangeiro (VO e DAO) ?
Obrigada!

J

acho que seria algo assim:

public class ClasseEstrangeira&#123;
   private int id;
   private String nome;
   //get &amp; set
&#125;

public class OutraClasse&#123;
   private int id;
   private ClasseEstrangeira estrangeira;
   private String dado;
&#125;

&lt;class name=&quot;ClasseEstrangeira&quot; table=&quot;estrangeiras&quot;&gt;
   &lt;id name=&quot;id&quot;&gt;
      &lt;generator class=&quot;native&quot; /&gt;
   &lt;/id&gt;
   &lt;property name=&quot;nome&quot; /&gt;
&gt;

&lt;class name=&quot;OutraClasse&quot; table=&quot;outras&quot;&gt;
   &lt;composite-id&gt;
      &lt;key-property name=&quot;chave&quot; column=&quot;chave&quot; /&gt;
      &lt;key-many-to-one name=&quot;estrangeira&quot; class=&quot;ClasseEstrangeira&quot; column=&quot;estrangeira&quot;/&gt;
   &lt;/composite-id&gt;
   &lt;property name=&quot;dado&quot; /&gt;
&lt;/class&gt;

Qual o erro dá?

M

Eu estou fazendo exatamente assim!!!
Mas não tem um lance de que, quando usamos composite-ID, tem que ser feita uma classe representando apenas o composite-ID??? Acho que o meu erro está aí…nao estou sabendo fazer certo…
AH! O erro dá na hora em que eu clico no botão Inserir…o JSP que acusa o erro (Tomcat). A mensagem se refere a erro no mapeamento.

J

Ahh esqueci, as classe que usam composite-id devem ser serializaveis e implementar os metodos equals() e hashCode(). :oops:

Implementa aí…

M

Eu uso HashSet no caso na ClasseEstrangeira…faço assim:

Set outrasclasses = new HashSet()
//get e set para outrasclasses

Como assim implementar os métodos equals e HashCode?
A ClasseEstrangeira e OutraClasse devem ser serializable???

J

Veja:

public class ClasseEstrangeira implements Serializable&#123;
   private int id;
   private String nome;
   //get &amp; set

   public boolean equals&#40;Object obj&#41;&#123;
      if&#40;!&#40;obj instaceof ClasseEstrangeira&#41;&#41;&#123;
         return false;
      &#125;

      ClasseEstrangeira ce = &#40;ClasseEstrangeira&#41; obj;
      return getId&#40;&#41;==ce.getId&#40;&#41;;
   &#125;

   public int hashCode&#40;&#41;&#123;
      return Integer.valueOf&#40;getId&#40;&#41;&#41;.hashCode&#40;&#41;;
   &#125;
&#125; 

public class OutraClasse implements Serializable&#123;
   private int id;
   private ClasseEstrangeira estrangeira;
   private String dado;

   public boolean equals&#40;Object obj&#41;&#123;
      if&#40;!&#40;obj instanceof OutraClasse&#41;&#41;&#123;
         return false;
      &#125;

      OutraCasse oc = &#40;OutraClasse&#41; obj;
      return &#40;getId&#40;&#41;==oc.getId&#40;&#41;&amp;&amp;getEstrangeira&#40;&#41;.equals&#40;oc.getEstrangeira&#40;&#41;&#41;;
   &#125;
 
   public int hashCode&#40;&#41;&#123;
      return 37*&#40;Integer.valueOf&#40;getId&#40;&#41;&#41;.hashCode&#40;&#41;+getEstrangeira&#40;&#41;.hashCode&#40;&#41;&#41;;
   &#125;
&#125;

Não sei se as implementações estão totalmente certas não, porque fiz rapido aqui, mas testa aí...

ps.: pra saber mais sobre equals() e hashCode():

http://mindprod.com/jgloss/hashcode.html

M

eu fiz exatamente o que vc falou.
Mas em OutraClasse…o q eu coloco como o id?
Esta OutraClasse é exatamente a que se refere à tabela com chave composta. Uma das chaves é um timestamp :dt_cadastro…e a outra chave é o id_usuario ( que vem da minha tabela estrangeira (usuario). Como q eu faço neste caso?
E me diga tambem onde eu vou utilizar este equals e hashcode…

Muito obrigada pela atenção dispensada…vc está sendo legal comigo

J

Nesse caso o que eu chamei de "id" é o seu dt_cadastro, é só substituir...

O metodo equals() você pode usar para saber se dois objetos são iguais...

ex.:

OutraClasse o1 = new OutraClasse&#40;&#41;;
OutraClasse o2 = new OutraClasse&#40;&#41;;

if&#40;o1.equals&#40;o2&#41;&#41;&#123;
   //os objetos são iguais
&#125;else&#123;
   //os objetos são diferentes
&#125;

O metodo hashCode() é usado para obter um codigo hash do objeto. E raramente é usado diretamente, quem usa muito isso são as coleções onde você coloca esse objeto, como um HashTable.

Nesse caso você não vai usar esses metodos, quem vai usar é o hibernate...

Mais detalhes em: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html

M

ahhh entendi !!!

só está me dando erro nesta linha:
seria o sinal ==mesmo ???
(getId()==oc.getId()&&getEstrangeira().equals(oc.getEstrangeira());

acho q estou chegando lá…

me diga uma coisa…no DAO como vou fazer para inserir os dados???

J

É o == mesmo, tente colocar as expressões entre parenteses…

No DAO é só você chamar o metodo save() de uma Session que ele vai salvar seu objeto…

ex.:

OutraClasse oc = new OutraClasse&#40;&#41;; //preenche com os dados Session sessao = sessionFactory.openSession&#40;&#41;; Transaction tsct = sessao.beginTransaction&#40;&#41;; sessao.save&#40;oc&#41;; tsct.commit&#40;&#41;; sessao.close&#40;&#41;;

M

concertei os parenteses…rssrrs

o erro agora está dando pq a minha chave Dt_cadastro pe timestamp.

public int hashCode(){
return 37*(Integer.valueOf(getDt_cadastro()).hashCode()+getUsuario().hashCode());

como eu faço no Integer.valueOf(getDt_cadastro() ??? se eu ter um getTime retorna um long e nao int…

My Goooooooddd rssrrs

J

É só tirar o Integer.valueOf()

M

ok…agora compilou.
Mas continua me dando o meeesmo erro no JSP…
Como seria a parte de código para eu inserir no banco justamente os campos referentes à chave composta? acho q é isto que está pegando…pq o meu DAO está igualzinho ao que vc mandou. E todo o código q vc me mandou eu implemente nos respectivos VO das classes OutraClasse e ClasseEstrangeira. Eu ainda acho q o q tá pegando é o DAO…

valeu mais uma vez

J

Qual o erro?

M

org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:848)

Este erro…de tanto apanhar com minhas outras tabelas q nao sao chave composta e q estao todas dando certo, acontece quando existe erro no mapeamento.
Vou almoçar e jah volto…
Existem alguns exemplos em q se existe uma classe para o composite-id…por exemplo uma classe Chave cujo os atributos sao as colunas pk. Já ouviu falar algo sobre? Como eu poderia aplicar o q vc me passou nisto?

J

Isso não é aplicado a Hibernate, isso é em Entity Bean…

Esse erro que você postou não mostra o erro do Hibernate, pegue o erro completo e coloque aí…

M

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException

org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:848)

org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:781)

org.apache.jsp.consulta_005fhist_005fusuario_jsp._jspService(consulta_005fhist_005fusuario_jsp.java:216)

org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)

javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:322)

org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:291)

org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)

javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:362)
J

Não está aparecendo erro nenhum de Hibernate aí não…

Tenta rodar isso fora desse JSP, em outra classe, uma aplicação Standalone, algo assim… pode rodar no debug tambem…

M

seu eu tiroi o key-many-to-one ele funciona perfeitamente do jeito q eu tinha feito. O tomcat nao reconhece erros de hibernate…por isto dah este erro. Nao adianta eu fazer standalone…o q eu tenho q entregar é JSP…bom…se nao puder me ajudar mais jah agradeco tudo ate agora…
até maiisss

J

Se você fizer standalone você pode debugar mais facil, ou simplesmente dar um printStackTrace() na exceção pra ver a mensagem… e no log do tomcat aparece o stack trace completo…

M

Eu entendi o q vc quis dizer…mas não foi preciso …rsrs
Este ocorre toda vez que algo está errado no xml (mapeamento), seja um caracter a mais, uma palavra a mais e q nao deveria estar lá.
Eu resolvi o meu problema, consegui com que minha aplicação reconhecesse um dos meus campos da chave composta como sendo um campo vindo de outra tabela.
Aquele lance de que é preciso uma classe exclusivamente para o composite-id é verdade…senão não funciona meeeesssmo! E aqueles lances dos metodos equals e hashcode eu nao precisei implementar não…mas deixei lá comentado.
Olha só a classe para o composite-id:
/*

  • CompositeIDHistUsuario.java
  • Created on 18 de Setembro de 2006, 11:03
  • To change this template, choose Tools | Template Manager
  • and open the template in the editor. */

package vo;

import java.io.Serializable;

public class HistUsuarioPK implements Serializable

{

//campo da classe a ser mapeada mesmo

private java.sql.Timestamp dt_cadastro;

//campo na classe a ser mapeada e que é foreing key, se instancia o objeto

private Usuario usuario;
public java.sql.Timestamp getDt_cadastro() {
    return dt_cadastro;
}

public void setDt_cadastro(java.sql.Timestamp dt_cadastro) {
    this.dt_cadastro = dt_cadastro;
}    

public Usuario getUsuario() {
    return usuario;
}

public void setUsuario(Usuario usuario) {
    this.usuario = usuario;
}

}
Este é o trecho no DAO…que era o que eu tinha dúvida:

depois dos comandos abrindo o hibernate e inserindo demais campos

(…)

// Chave Composta

Usuario usuario=new Usuario();

//o id_usuario eu passei como parametro

usuario = (Usuario)sessao.get(Usuario.class, id_usuario);

HistUsuarioPK ch= new HistUsuarioPK();

ch.setDt_cadastro(dt_cadastro);

ch.setUsuario(usuario);

hist_usuario.setChave(ch);
sessao.save(hist_usuario);
        
        transacao.commit();
        sessao.close();
        
    } catch (Exception ex) {
        ex.printStackTrace();
        return false;
    }

e a parte do composite Id no mapeamento ficou assim:

<composite-id name=“Chave” class=“HistUsuarioPK”>

<key-property name=“Dt_cadastro” type=“timestamp”>

<column name=“dt_cadastro”/>

</key-property>
&lt;key-many-to-one name="Usuario"&gt;
            &lt;column name="id_usuario"/&gt;
        &lt;/key-many-to-one&gt;
    &lt;/composite-id&gt;

tirei uns atributos do key-many-to-one pq estavam fazendo não dar certo.
BOm colega, é isto. MUITO OBRIGADA PELA ATENÇÃO!!!

M

AH! o que é classpath é sacanagem pow…foi vc quem colocou isto pra mim? srrssrrs

J

Maravilha que funcionou…

Mas esse negocio de criar uma classe pra chave da classe é opicional, apesar do pessoal do Hibernate recomenda-la, eu sempre usei sem criar essa classe, mas se no seu caso é melhor assim, otimo então…

Se você precisar consultar no futuro:
http://www.hibernate.org/hib_docs/v3/reference/en/html/mapping.html#mapping-declaration-compositeid

J

Não, não. Isso é automatico, é baseado na quantidade de mensagens que você tem no forum…

Criado 19 de setembro de 2006
Ultima resposta 20 de set. de 2006
Respostas 25
Participantes 2