Problemas com Mapeamento Hibernate

Boa Tarde,

Eu não entendi como precisa ser feito via Hibernate o mapeamento que descrevo abaixo.
Existe uma tabela chamada TAB_CATEGORIA que represente, como o nome diz, uma categoria.

Uma categoria pode ter 0 ou mais categorias filhas dela. Este relacionamento de pertinência é dado pelo campo idPai.
Ou seja, para ver todas categorias filhas de uma categoria eu preciso fazer um SQL

O Problema é que não sei como fazer este mapeamento no Hibernate através de anotações.
Eu tentei fazer como mostrado em meu código abaixo, mas não estou tendo sucesso. Podem me ajudar?

@NamedQueries( {
	@NamedQuery(name = "Categoria.obterListaCategoria", 
			query = "FROM Categoria C " + 
			"ORDER BY C.nome"),
	@NamedQuery(name = "Categoria.obterListaRootCategoria", 
			query = "FROM Categoria C " + 
			"WHERE (C.idPai = -1) " + 
			"ORDER BY C.nome"),
	@NamedQuery(name = "Categoria.obterCategoriasFilho", 
			query = "FROM Categoria C " +
			"WHERE (C.idPai = :IdPaiCategoria) " +
			"ORDER BY C.nome") })

@Entity
@Table(name = "TAB_CATEGORIA")
@SequenceGenerator(name = "CATEGORIA_SEQ", sequenceName = "CATEGORIA_SEQ")
/**
 * Forma de organizar hierarquicamente um produto.
 * Uma categoria pode ter uma ou mais sub categorias.
 * Uma categoria pode ter uma ou nenhuma categoria pai.
 */
public class Categoria implements Serializable{

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "CATEGORIA_SEQ")
	@Column(name = "ID_CATEGORIA")
	private int id;

	@Column(name = "NM_CATEGORIA")
	private String nome;

	@JoinColumn(name = "ID_CATEGORIA",referencedColumnName="IDPAI_CATEGORIA")
	@Column(name = "IDPAI_CATEGORIA")
	private int idPai;

	@OneToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY )
	@JoinTable(name="Categoria")
	private List<Categoria> filhos;
	

	public List<Categoria> getFilhos() {
		return filhos;
	}

	public void setFilhos(List<Categoria> filhos) {
		this.filhos = filhos;
	}

	public static List<Categoria> obterListaCategoria() {

		Session session = HibernateUtil.getSessionFactory().openSession();
		org.hibernate.Query q = session
				.getNamedQuery("Categoria.obterListaCategoria");

		List<Categoria> resultado = q.list();
		session.close();

		return resultado;
	}

	public static List<Categoria> obterListaRootCategoria() {
		return obterCategoriasFilho(-1);
	}

	public int getId() {
		return this.id;
	}

	public int getIdPai() {
		return idPai;
	}

	public String getNome() {
		return this.nome;
	}

	public void setId(int id) {
		this.id = id;
	}

	public void setIdPai(int idPai) {
		this.idPai = idPai;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}
	
	public String toString(){
		StringBuilder builder = new StringBuilder();
		builder.append("{id=").append(this.id).append(" ,nome=").append(this.nome).append(" ,pai=").append(this.idPai).append("}");
		return builder.toString();
	}

}

Cara o lado one fica ± assim:

@OneToMany(cascade = CascadeType.PERSIST.REFRESH, mappedBy = "cidadeid")
	private Collection&lt;EnderecoCobranca&gt; endEntregaclienteCollection;

e tem que mapear no lado many ± assim:


@JoinColumn(name = "cidadeid", referencedColumnName = "cidadeid")
	@ManyToOne
	private Cidade cidadeid;

Desculpe, mas acho que não fui claro na dúvida. :slight_smile:
O Problema é que a entidade tem um relacionamento de 1 para n com ela mesma.

Na classe existe o Javadoc que mostra exatamente o relacionamento.

[code]/**

  • Forma de organizar hierarquicamente um produto.
  • Uma categoria pode ter uma ou mais sub categorias.
  • Uma categoria pode ter uma ou nenhuma categoria pai.
    */ [/code]
    Por sub categoria entenda-se um outro elemento da mesma classe chamada categoria. Idêntico como objeto e mapeado para a mesma tabela.
    O relacionamento está entre o id e o idPai.

o idPai é o id da categoria pai.
Exemplo:
Categoria 1: id=1, nome=Teste 0, idPai=-1
Categoria 2: id=2, nome=Filha de Teste 1, idPai=1
Categoria 3: id=3, nome=Filha de Teste 2, idPai=1

Quando eu executar o método getFilhos da instância da classe Categoria que armazena Categoria 1 ele deverá me retornar uma List formada pela Categoria 2 e Categoria 3.
A Query SQL que deveria fazer isso é:

Entendeu? :slight_smile:

A dúvida é como mapear/anotar o metodo getFilhos e os campos pertinentes na classe Categoria.

Uma alternativa, caso não seja possível fazer esse relacionamento sem uma tabela auxiliar, seria usar uma tabela extra chamada TAB_CATEGORIA_TAB_CATEGORA que teria apenas o idPai e idFilho.

CREATE TABLE TAB_CATEGORIA_TAB_CATEGORA(idPai NUMBER, idFilho NUMBER);

TAB_CATEGORIA_TAB_CATEGORA.idPai haveria um relacionamento com TAB_CATEGORIA.id
TAB_CATEGORIA_TAB_CATEGORA.idFilho haveria um relacionamento com TAB_CATEGORIA.id

E ai a amarração seria feita.

Seria o equivalente a, em SQL, usar a seguinte query para obter os dados desejados:

SELECT 
  C.id, 
  C.nome
FROM 
  TAB_CATEGORIA C, 
  TAB_CATEGORIA_TAB_CATEGORIA XC 
WHERE 
  C.id = XC.idPai AND
  XC.idPai = ?

Usando esta abordagem, como ficaria o mapeamento em anotações da classe Categoria?

Obrigado,

Consegui o que queria de uma outra forma.

package com.jasp.hierarchy;

import java.io.Serializable;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

import org.hibernate.Transaction;
import org.hibernate.classic.Session;

import com.jasp.util.HibernateUtil;

@NamedQueries( {
		@NamedQuery(name = "Categoria.obterListaCategoria", query = "FROM Categoria C "
				+ "ORDER BY C.nome"),
		@NamedQuery(name = "Categoria.obterListaRootCategoria", query = "FROM Categoria C "
				+ "WHERE (C.idPai = -1) " + "ORDER BY C.nome"),
		@NamedQuery(name = "Categoria.obterCategoriasFilho", query = "FROM Categoria C "
				+ "WHERE (C.idPai = :IdPaiCategoria) " + "ORDER BY C.nome") })
@Entity
@Table(name = "TAB_CATEGORIA")
@SequenceGenerator(name = "CATEGORIA_SEQ", sequenceName = "CATEGORIA_SEQ")
/*
 * Forma de organizar hierarquicamente um produto. Uma categoria pode ter uma ou
 * mais sub categorias. Uma categoria pode ter uma ou nenhuma categoria pai.
 */
public class Categoria implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "CATEGORIA_SEQ")
	@Column(name = "ID_CATEGORIA")
	private int id;

	@Column(name = "NM_CATEGORIA")
	private String nome;

	@Column(name = "IDPAI_CATEGORIA")
	private int idPai;

	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinTable(name = "Categoria")
	private List<Categoria> filhos;

	public List<Categoria> getFilhos() {
		filhos = obterCategoriasFilho(id);
		return filhos;
	}

	public void setFilhos(List<Categoria> filhos) {
		Session session = HibernateUtil.getSessionFactory().openSession();
		Transaction t = session.beginTransaction();
		for (Categoria filho : filhos) {
			filho.setIdPai(this.id);
			session.save(filho);
		}
		this.filhos = filhos;
		t.commit();
		session = null;
		t = null;
	}

	@SuppressWarnings("unchecked")
	private static List<Categoria> obterCategoriasFilho(int IdPaiCategoria) {
		Session session = HibernateUtil.getSessionFactory().openSession();
		org.hibernate.Query q = session
				.getNamedQuery("Categoria.obterCategoriasFilho");

		q.setParameter("IdPaiCategoria", IdPaiCategoria);
		List<Categoria> resultado = q.list();
		session.close();
		session = null;
		return resultado;
	}

	public static List<Categoria> obterListaCategoria() {

		Session session = HibernateUtil.getSessionFactory().openSession();
		org.hibernate.Query q = session
				.getNamedQuery("Categoria.obterListaCategoria");

		List<Categoria> resultado = q.list();
		session.close();

		return resultado;
	}

	public static List<Categoria> obterListaRootCategoria() {
		return obterCategoriasFilho(-1);
	}

	public int getId() {
		return this.id;
	}

	public int getIdPai() {
		return idPai;
	}

	public String getNome() {
		return this.nome;
	}

	public void setId(int id) {
		this.id = id;
	}

	public void setIdPai(int idPai) {
		this.idPai = idPai;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("{id=").append(this.id).append(" ,nome=").append(
				this.nome).append(" ,pai=").append(this.idPai).append("}");
		return builder.toString();
	}

}