Mapeamento Um para Um em Hibernate com JPA

Mapeamento Um para Um em Hibernate com JPA

O Hibernate é um framework de mapeamento objeto-relacional. A sua finalidade é a comunicação entre as classes da aplicação e o banco de dados e assim substituindo o JDBC. O Hibernate possui a sua linguagem SQL (Structures Query Language) que é chamada de HQL (Hibernate Query Language).

Os comandos SQL atuam na estrutura da tabela, por exemplo : select * from venda. Os comandos HQL atuam nas classes de aplicação, por exemplo: session.createQuery(“from Venda”).list() .

O hibernate possui dois arquivos de configuração o hibernate.cfg.xml e a classe HibernateUtil. O arquivo hibernate.cfg.xml tem a configuração básica para acessar o banco de dados e o mapeamento das classes da aplicação. A Classe hibernateUtil tem a finalidade de gerenciar a conexão com o banco de dados através do componente SessionFactory.

Para construir o mapeamento do hibernate é importante:
1- Definir a classe que irá receber o mappeby.
2- E a outra classe irá receber o JoinColumn.

A lista das bibliotecas (arquivos .jar) do Oracle, Hibernate e Servlet 3.0 necessários são:

antlr-2.7.6.jar commons-fileupload-1.0.jar jakarta-oro.jar
asm-attrs.jar commons-lang-2.1.jar javaee.jar
asm.jar commons-logging-1.1.1.jar jstl-1.1.0.jar
c3p0-0.9.0.jar commons-validator.jar jstl.jar
cglib-2.1.3.jar dom4j-1.6.1.jar jta.jar
commons-beanutils-1.8.0.jar ejb3-persistence.jar log4j-1.2.15.jar
commons-codec-1.3.jar hibernate-annotations.jar ojdbc14.jar
commons-collections-3.2.1.jar hibernate-commons-annotations.jar oro-2.0.8.jar
commons-digester-2.0.jar hibernate3.jar servlet-api.jar
commons-el-1.0.jar hsqldb.jar standard.jar

Arquivos de Configuração do Hibernate

oracle_hibernate_cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
  
    <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
    <property name="hibernate.connection.url">jdbc:oracle:thin:@127.0.0.1:1521:XE</property>
    <!-- Usuario do banco de dados, exemplo system -->
    <property name="hibernate.connection.username">usuario</property>

    <!-- Senha do Usuario do banco de dados  -->    
    <property name="hibernate.connection.password">senha</property>
    
    <!-- Mostra todo o codigo sql no console -->
    <property name="hibernate.show_sql">true</property>
    
    <!-- Mostra o sql formatado no console -->
    <property name="hibernate.format_sql">true</property>
    
    <!-- Classes da Aplicação Mapeadas -->
    <mapping class="entity.Venda"/>
    <mapping class="entity.Produto"/>
    
  </session-factory>
</hibernate-configuration>    

HibernateUtil.java

package persistence;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

// Função para abrir a conexao com o banco de dados
public class HibernateUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            
            sessionFactory = new AnnotationConfiguration().
            		configure("config/oracle_hibernate.cfg.xml").buildSessionFactory();
        } catch (Throwable ex) {
            
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}    

CalculoProduto.java

package control;

import entity.Produto;

public class CalculoProduto {
	
	public void calculoValorTotalProduto(Produto p){
		p.setValorTotal(p.getPreco() * p.getQuantidade());
	}
}       

Mapeamento das classes Venda e Produto.

Obs: Os imports do JPA (Java Persistence API) vem a biblioteca javax.persistence.*.

package entity;

import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@SequenceGenerator(name="seqVenda", sequenceName="seqVenda")
public class Venda {
	
	@Id
	@GeneratedValue(generator="seqVenda")
	private Integer idVenda;
	
	@Temporal(TemporalType.DATE)
	@Column(length=25)
	private Date dataCompra; 
	//fetch -> Em um relacionamento forte logo buscando venda 
	//podemos trazer o produto associado.
	//CascadeType -> Serve para deletar ou alterar em conjunto, ou seja,
	//Se deletar ou alterar um objeto de venda automaticamente 
	//é deletado ou alterado um objeto de produto no banco de dados
	@OneToOne(mappedBy="venda",fetch=FetchType.EAGER, cascade={CascadeType.ALL})
	private Produto produto;
	
	public Venda() {
		// TODO Auto-generated constructor stub
	}

	public Venda(Integer idVenda, Date dataCompra) {
		super();
		this.idVenda = idVenda;
		this.dataCompra = dataCompra;
	}

	@Override
	public String toString() {
		return "Venda [idVenda=" + idVenda + ", dataCompra=" + dataCompra
				+ ", produto=" + produto + "]";
	}

	public Integer getIdVenda() {
		return idVenda;
	}
	public void setIdVenda(Integer idVenda) {
		this.idVenda = idVenda;
	}
	public Date getDataCompra() {
		return dataCompra;
	}
	public void setDataCompra(Date dataCompra) {
		this.dataCompra = dataCompra;
	}
	public Produto getProduto() {
		return produto;
	}
	public void setProduto(Produto produto) {
		this.produto = produto;
	}
}    
package entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Transient;

@Entity
@SequenceGenerator(name="seqProduto", sequenceName="seqProduto")
public class Produto {
	
	@Id
	@GeneratedValue(generator="seqProduto")
	private Integer idProduto;
	
	@Column(length=35)
	private String nomeProduto;
	
	@Column
	private Double preco;
	
	@Column
	private Integer quantidade;
	
	//Campo que não fará parte da tabela do banco de dados
	@Transient
	private Double valorTotal;
	
	@OneToOne
	@JoinColumn(name="id_venda")
	private Venda venda;
	
	{
		valorTotal = 0.;
	}
	
	
	public Produto() {
		// TODO Auto-generated constructor stub
	}

	public Produto(Integer idProduto, String nomeProduto, Double preco,
			Integer quantidade) {
		super();
		this.idProduto = idProduto;
		this.nomeProduto = nomeProduto;
		this.preco = preco;
		this.quantidade = quantidade;
	}

	@Override
	public String toString() {
		return "Produto [idProduto=" + idProduto + ", nomeProduto="
				+ nomeProduto + ", preco=" + preco + ", quantidade="
				+ quantidade + ", valorTotal=" + getValorTotal() + "]";
	}

	public Integer getIdProduto() {
		return idProduto;
	}
	public void setIdProduto(Integer idProduto) {
		this.idProduto = idProduto;
	}
	public String getNomeProduto() {
		return nomeProduto;
	}
	public void setNomeProduto(String nomeProduto) {
		this.nomeProduto = nomeProduto;
	}
	public Double getPreco() {
		return preco;
	}
	public void setPreco(Double preco) {
		this.preco = preco;
	}
	public Integer getQuantidade() {
		return quantidade;
	}
	public void setQuantidade(Integer quantidade) {
		this.quantidade = quantidade;
	}
	public Double getValorTotal() {		
		return valorTotal;
	}
	public void setValorTotal(Double valorTotal) {
		this.valorTotal = valorTotal;
	}
	public Venda getVenda() {
		return venda;
	}
	public void setVenda(Venda venda) {
		this.venda = venda;
	}
}    

Classe para executar automaticamente o script do banco de dados baseado no mapeamento feito nas classes.

package config;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

// Classe para gerar o banco de dados apartir do mapeamento das classe no oracle_hibernate.cfg.xml

public class Main {
	
	public static void main(String[] args) {		
		Configuration cfg = new AnnotationConfiguration().configure("config/oracle_hibernate.cfg.xml");
		new SchemaExport(cfg).create(true, true);		
	}
}    

VendaDao.java

Obs: Os imports dos atributos vem da biblioteca org.hibernate.*;
A class abaixo tem a função de executar toda a lógica do CRUD.

package persistence;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;

import entity.Produto;
import entity.Venda;

public class VendaDao {
	
	Session session; // Abre a conexão com o banco
	Transaction transaction; // Abre a transaction para as operações com a tabela
	Criteria criteria; // Busca na tabela por classe
	Query query; // Busca na tabela por HQL
	

	
	public void create( Venda v , Produto p ) throws Exception{		
		session = HibernateUtil.getSessionFactory().openSession();
			transaction = session.beginTransaction();
				session.save(v); //Gravo a tabela mais forte (Sem chave estrangeira)
				p.setVenda(v); //Armazena a chave primaria para ser utilizada como chave
							   // estrangeira na tabela mas fraca
				session.save(p); //Grava a tabela mas fraca (com chave estrangeira)
			transaction.commit();
		session.close();
	}
	
	public void delete(Venda v ) throws Exception{		
		session = HibernateUtil.getSessionFactory().openSession();
			transaction = session.beginTransaction();
				session.delete(v);
			transaction.commit();
		session.close();
	}
	
	public void update( Venda v ) throws Exception{		
		session = HibernateUtil.getSessionFactory().openSession();
			transaction = session.beginTransaction();
				session.update(v);
			transaction.commit();
		session.close();
	}
	
	public Venda findByCod(Integer cod) {		
		session = HibernateUtil.getSessionFactory().openSession();
			Venda venda = (Venda) session.get(Venda.class, cod);
		session.close();
		return venda;
	}
	
	public List findAllQuery() {
		
		session = HibernateUtil.getSessionFactory().openSession();
			List lista = session.createQuery("from Venda").list();
		session.close();
		return lista;
	}

	public List findAllCriteria() {
		
		session = HibernateUtil.getSessionFactory().openSession();
			List lista = session.createCriteria(Venda.class).list();
		session.close();
		return lista;
	}
	
	// Utilizando o SQL normal	
	public List findAllSQL() {
		
		session = HibernateUtil.getSessionFactory().openSession();
			//Query SQL
			String texto = "select * from venda v INNER JOIN produto p ON v.idVenda = p.idProduto";
			//Executa a query acima
			SQLQuery query = session.createSQLQuery(texto);
			//Identifica a classe que irá receber a query
			query.addEntity(Venda.class);
			//Adiciona na lista			
			List lista = query.list();			
		session.close();
		return lista;
	}
}    

Executando na Classe Main

package main;

import java.util.Date;

import control.CalculoProduto;

import persistence.VendaDao;
import entity.Produto;
import entity.Venda;

public class Main {

	public static void main(String[] args) {

		CalculoProduto cp = new CalculoProduto();	
		Venda v = new Venda(null, new Date("05/02/2010"));
		Produto p = new Produto(null, "arroz", 10., 5);
		
		try {
	
			new VendaDao().create(v, p);

			System.out.println( "Dados Gravados" );

			for(Venda v1 : new VendaDao().findAllQuery()){
				//Calcular o valor do Produto
				cp.calculoValorTotalProduto(v1.getProduto());	
				System.out.println("QUERY: " + v1 );	
			}
			
			// Buscar o Registro no banco
			Venda venda = new VendaDao().findByCod(1);
			
			// Atualizando algumas informações do registro buscado no banco
			venda.setDataCompra(new Date("15/07/2012"));
			venda.getProduto().setNomeProduto("feijao");
			venda.getProduto().setPreco(5.5);
			venda.getProduto().setQuantidade(10);			
			
			// Atualizar o registro 1
			new VendaDao().update(venda);

			for(Venda v1 : new VendaDao().findAllCriteria()){
				//Calcular o valor do Produto
				cp.calculoValorTotalProduto(v1.getProduto());	
				System.out.println("CRITERIA: " + v1 );	
			}
			
			// Buscar o Registro no banco
			Venda venda1 = new VendaDao().findByCod(1);

			// Deletar o registro 1
			new VendaDao().delete(venda1);
			
			for(Venda v1 : new VendaDao().findAllSQL()){
				//Calcular o valor do Produto
				cp.calculoValorTotalProduto(v1.getProduto());	
				System.out.println("SQL: " + v1 );	
			}
			
		} catch (Exception e) {
			System.out.println("Error " + e.getMessage());
		}
	}
}