Relacionamento Hibernate

Vejam a seguinte situação:

Tabela Pergunta

ID          Pergunta
1            Perg1
2            Perg2
3            Perg3

Tabela Resposta

ID            Resposta
1              Resp1
2              Resp2
3              Resp3

Tabela PerguntaResposta

IDPergunta          IDResposta
1                         1
1                         2
1                         3

Eu tentei criar uma tabela para associar os ID de perguntas e respostas mas durante a apresentação, os dados vieram todos com problemas, imaginei que deveria fazer alguma configuração de sobre relacionamento no hbm.xml, e apesar d ter visto alguns exemplos ainda não obtive sucesso.
Alguém poderia mostrar como devo fazer esta configuração?

Segue abaixo os meus hbm.xml

Pergunta.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
	<class name="br.com.tutorialfmu.questionario.Pergunta" table="pergunta">
		<id name="id" column="id" type="int">
			<generator class="assigned" />
		</id>
		<property name="pergunta" column="pergunta" type="string" />
	</class>
</hibernate-mapping>
Resposta.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
	<class name="br.com.tutorialfmu.questionario.Resposta" table="pergunta">
		<id name="id" column="id" type="int">
			<generator class="assigned" />
		</id>
		<property name="resposta" column="resposta" type="string" />
	</class>
</hibernate-mapping>

Obrigado!

Primeiro, vc está mapeando os dois xmls para a mesma tabela (pergunta)!!!

Outra questão é se a sua pergunta pode possuir diversas respostas e se sua resposta pode pertencer a mais de uma pergunta, se for verdade temos uma situação many-to-many (aparentemente, esse é o caso, já q vc criou uma tabela de vínculo). Para essas situações vc pode por uma coleção na Pergunta para pegar as respostas vinculadas, para isso vc pode adicionar o seguinte ao seu mapeamento da pergunta (ou uma das variações que vc pode olhar na documentação):

<set name="respostas" table="PerguntaResposta ">
  <key column="IDPergunta"/>
  <many-to-many class="Resposta" column="IDResposta"/>
</set>

Ai vc tem que colocar um Set para as respostas na classe de pergunta e criar o get e set para o mesmo…

Isso é apenas um exemplo, de uma olhada na documentação sobre many-to-many!!!

Fallow

TedLoprao vc poderia explicar + ou - como esse mapeamento funciona?

acima vc diz para eu criar um método onde tem uma query para consultar as respostas das perguntas? Algo como:

select resposta from br.com.tutorialfmu.questionario.Resposta as resposta where resposta.id = 1 [/quote]

Nop!!!

Vc coloca um Set de respostas na classe Pergunta… Ok… dai vc cria o get e o set normalmente para o Set de respostas:

private Set respostas;

public Set getRespostas() {
  return respostas;
}

public void setRespostas(Set resp) {
  this.respostas = resp;
}

Ai vc coloca aquele esquema no mapeamento da Pergunta…

Ao fazer o load ele irá carregar as respostas para vc automaticamente!!!

Mais ou menos isso, tlvz tenha que fazer uns ajustes, mas é por aí!!!

Fallow

TedLoprao, tentei seguir suas orientações mas não obtive sucesso cara.
Eu só mudei um pouco o escopo, pois agora estou tentando fazer um relacionamento de one-to-many. As tabelas no banco de dados estão criadas e devidamente relacionadas.
Abaixo vou colocar o erro e o meu fonte.

Erro retornado pelo tomcat

INFO: processing one-to-many association mappings
net.sf.hibernate.MappingException: Association references unmapped class: br.com
.tutorialfmu.questionario.PerguntaBean
        at net.sf.hibernate.cfg.Binder.bindCollectionSecondPass(Binder.java:1162
)
        at net.sf.hibernate.cfg.Binder$CollectionSecondPass.secondPass(Binder.ja
va:1366)
        at net.sf.hibernate.cfg.Binder$SecondPass.doSecondPass(Binder.java:1342)

        at net.sf.hibernate.cfg.Configuration.secondPassCompile(Configuration.ja
va:618)
        at net.sf.hibernate.cfg.Configuration.buildSessionFactory(Configuration.
java:761)
        at br.com.tutorialfmu.questionario.MateriaDAO.<init>(MateriaDAO.java:13)

        at br.com.tutorialfmu.aluno.AlunoController.doGet(AlunoController.java:6
9)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:743)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl
icationFilterChain.java:284)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF
ilterChain.java:204)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperV
alve.java:257)
        at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValv
eContext.java:151)

MateriaBean.java

package br.com.tutorialfmu.questionario;

import java.io.Serializable;
import java.util.Set;

public class MateriaBean implements Serializable {
    
   private int id;
   private String nome;
   private Set pergunta;

   public MateriaBean() {}
   
   public int getId() {
      return id;
   }
   
   public int setId(int id) {
      return this.id = id;
   }
   
   public String getNome() {
      return nome;
   }
   
   public String setNome(String nome) {
      return this.nome = nome;
   }
   
   public void setPergunta(Set pergunta) {
       this.pergunta = pergunta;
   }
   
   public Set getPergunta() {
       return pergunta;
   }
   
}

PerguntaBean.java

package br.com.tutorialfmu.questionario;

import java.io.Serializable;

public class PerguntaBean implements Serializable {
    
    private int id;
    private String pergunta;
    private String imagem;
    private String tipo;
    private boolean respondida = false;
    private boolean correta = false;
    
    public PerguntaBean() {}
    
    public void setId(int id) {
        this.id = id;
    }
    
    public int getId() {
        return id;
    }
    
    public void setPergunta(String pergunta) {
        this.pergunta = pergunta;
    }
    
    public String getPergunta(){
        return pergunta;
    }
    
    public void setImagem(String imagem) {
        this.imagem = imagem;
    }
    
    public String getImagem() {
        return imagem;
    }
    
    public void setTipo(String tipo) {
        this.tipo = tipo;
    }
    
    public void setRespondida(boolean respondida) {
        this.respondida = respondida;
    }
    
    public boolean getRespondida() {
        return respondida;
    }
    
    public void setCorreta(boolean correta) {
        this.correta = correta;
    }
    
    public boolean getCorreta() {
        return correta;
    }
}

MateriaBean.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
	<class name="br.com.tutorialfmu.questionario.MateriaBean" table="materia">
		<id name="id" column="id" type="int">
			<generator class="assigned" />
		</id>
		<set name="pergunta" inverse="true" lazy="true">
			<key column="id_materia" />
			<one-to-many class="br.com.tutorialfmu.questionario.PerguntaBean" />
		</set>
		<property name="nome" column="nome" type="string" />
	</class>
</hibernate-mapping>

PerguntaBean.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
	<class name="br.com.tutorialfmu.questionario.PerguntaBean" table="pergunta">
		<id name="id" column="id" type="int">
			<generator class="assigned" />
		</id>
		<many-to-one name="materia" class="br.com.tutorialfmu.questionario.MateriaBean" column="id_materia" not-null="true" />
		<property name="pergunta" column="pergunta" type="string" />
		<property name="imagem" column="imagem" type="string" />
	</class>
</hibernate-mapping>

Tem certeza q vc colocou o arquivo hbm do PerguntaBean na lista de mapeamentos ??? Esse erro ocorre quando vc não declara um determinado mapeamento…

Desculpa a minha ignorância, hehehe. Mas eu desconheço esse mapeamento que vc esta dizendo.
Sobre a localização dos arquivos eu fiz o seguinte: Tanto a classe quanto o hbm eu deixei no mesmo diretório e sempre me pareceu suficiente isso pq antes de tentar relacionar as tabelas eu consegui fazer persistência de uma tabela.

Faltou alguma coisa? :oops:

Vc está usando o esquema do DataStore para criar a SessionFactory??? como no exemplo aqui no GUJ???

  // powered by Daniel Quirino 
  Datastore datastore = Hibernate.createDatastore();
  datastore.storeClass(suaClasse.class);
  factory = datastore.buildSessionFactory();

Vc faz isso para vincular suas classes???

Faço assim…

import net.sf.hibernate.*; 
import net.sf.hibernate.cfg.*; 

public class MateriaDAO { 
    
    private SessionFactory factory; 
    
    public MateriaDAO() throws Exception { 
        Configuration cfg = new Configuration(); 
        cfg.addClass(br.com.tutorialfmu.questionario.MateriaBean.class); 
        factory = cfg.buildSessionFactory(); 
    } 
    
    public java.util.List getMateria() throws Exception { 
        Session session = factory.openSession(); 
        java.util.List materia = session.find("from br.com.tutorialfmu.questionario.MateriaBean"); 
        return materia; 
    } 
}

Ai é que está o problema… Se vc acessar o da Materia ele só vai carregar o mapeamento da MateriaBean e não o do PerguntaBean…

Outra coisa, essa configuração devia ocorrer uma vez para o seu sistema e deveria existir uma SessionFactory apenas…
Pense no seguinte, agora vc está carregando um mapeamento por vez, mas se vc carregar uma estrutura muito complexa (no seu exemplo vc tem dois mapeamentos para carregar), com um grande grafo de objetos, sempre que vc criar o DAO ele irá carregar todos esses mapeamentos de novo e isso ficará bastante lento…

Talvez o melhor fosse carregar em um Singleton ou algo assim, fazendo toda a configuração de uma vez, mas apenas uma vez!!!

Fallow

É verdade, eu vi isso na documentação do hibernate, depois vou fazer estas alterações.

Mas o seguinte, para que eu consiga fazer carregar as perguntas de uma determinada matéria, eu apenas devo acrescentar mais uma linha no meu contrutor, assim:

cfg.addClass(br.com.tutorialfmu.questionario.PerguntaBean.class);

ou tem algo mais a fazer??

a princípio é isso mesmo!!!

TedLoprao, obrigado por clarear as idéias… :slight_smile:

Eu vou fazer o acréscimo no meu contrutor da linha e ver o resultado.
Assim q testar direi se funcionou!

Falow!

TedLoprao, testei e funcionou, parou de exibir a mensagem de erro! :slight_smile: Porém…porém…porém aconteceu algo muito estranho e não sei dizer se o hibernate tem culpa nisso, veja só:

Vamos dizer que tenha uma linha no banco de dados com o valor

o que é lógica

A saída no meu browser fica

o que ??ca? 

Porém se eu não acentuar a saída da String é correta. Tem alguma coisa a ser configurada ainda?

Obs.: Para exibir eu populo uma List e passo por Sessão e exibo em uma JSP.

Hmmm, isso é problema de encoding… Tem várias mensagens sobre isso aqui no guj!!! De repente tu encontre alguma solução… Realmente eu nunca tive esse problema e não saberia te ajudar!!

Fallow

Blz cara, vou pesquisar por aí sobre o assunto!

Já tive um ótimo progresso com sua ajuda!
Tenho certeza q vou errar ainda um pouco no uso do hibernate pq é um pouco diferente de se trabalhar, mas é assim mesmo quando se está aprendendo!

Falow!