/home/ericogr/blog

Experiências no desenvolvimento de aplicações e afins

Criando relacionamentos com JPA

Posted by ericogr em 22 abril 2008

Vamos criar relacionamentos com JPA? Como nos exemplos anteriores, focarei nos aspectos práticos fornecendo exemplos simplificados.

Os seguintes relacionamentos podem ser mapeados com JPA:

  • OneToOne
  • OneToMany
  • ManyToOne
  • ManyToMany

Também podemos usar genéricos para especificar os tipos de coleções persistidas. Elas podem ser:

  • java.util.Collection
  • java.util.Set
  • java.util.List
  • java.util.Map

Vamos ver um exemplo usando as classes Nota, ItemNota, Produto e Fornecedor. O objeto nota tem um ou mais objetos itemNota. O objeto itemNota tem uma instancia da classe Produto e cada instancia de produto tem uma ou mais instancias da classe Fornecedor. A entidade itemNota tem referencia para a classe Nota.

Este exemplo está configurado para apagar e criar as tabelas do banco de dados a cada nova execução, ou seja, cada vez que este exemplo for executado, as informações anteriores serão perdidas. Veja a configuração do arquivo persistence.xml

[persistence.xml]

</persistence>

<?xml version=”1.0″ encoding=”UTF-8″?>
<persistence version=”1.0″
xmlns=”http://java.sun.com/xml/ns/persistence”&gt;
<persistence-unit name=”testeJpaPU” transaction-type=”RESOURCE_LOCAL”>
<provider>
oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
</provider>

<!– entidades –>
<class>com.wordpress.ericogr.entities.Nota</class>
<class>com.wordpress.ericogr.entities.ItemNota</class>
<class>com.wordpress.ericogr.entities.Produto</class>
<class>com.wordpress.ericogr.entities.Fornecedor</class>

<!– toplink/hsqldb –>
<properties>
<property name=”toplink.jdbc.url” value=”jdbc:hsqldb:hsql://localhost/testeJpa” />
<property name=”toplink.jdbc.user” value=”teste” />
<property name=”toplink.jdbc.driver” value=”org.hsqldb.jdbcDriver” />
<property name=”toplink.jdbc.password” value=”123456″ />
<property name=”toplink.target-database” value=”oracle.toplink.essentials.platform.database.HSQLPlatform”/>
<property name=”toplink.ddl-generation” value=”drop-and-create-tables” />
<property name=”toplink.logging.level” value=”FINEST” />
</properties>

</persistence-unit>

Em alguns relacionamentos, usamos como parâmetro das anotações o código (cascade = CascadeType.ALL). Isto serve para que as alterações realizadas no objeto que a contém sejam propagadas para os dependentes. Para persistir a coleção de itens da nota, precisamos desta anotação, pois do contrário os itens não seriam persistidos (na prática seria disparada uma exceção).

A entidade Nota tem um relacionamento bidirecional com a entidade ItemNota, onde uma nota pode conter um ou mais itens e um item contém uma única nota.

Abaixo está a classe Nota que representa a nota fiscal. Ela tem uma descrição, uma coleção de itens de nota fiscal e uma chave composta, representada pela classe NotaPk. Note que a propriedade getItensNota() foi anotada com @OneToMany(cascade = CascadeType.ALL, mappedBy = “nota”) onde mappedBy indica o nome da propriedade (no caso getNota()) da entidade dona do relacionamento (ItemNota). Aqui poderíamos omitir, pois o nome da entidade Nota é identico ao nome da propriedade na classe ItemNota, porém, para deixar mais claro, decidi colocar.

[Nota.java]

package com.wordpress.ericogr.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = “nota”)
public class Nota implements Serializable {
private String descricao;
private NotaPk notaPk;
private Collection<ItemNota> itensNota = new ArrayList<ItemNota>();

public Nota() {
}

public Nota(NotaPk notaPk) {
setNotaPk(notaPk);
}

@EmbeddedId
public NotaPk getNotaPk() {
return notaPk;
}

public void setNotaPk(NotaPk notaPk) {
this.notaPk = notaPk;
}

@Column(name = “descricao”, nullable = true)
public String getDescricao() {
return descricao;
}

public void setDescricao(String descricao) {
this.descricao = descricao;
}

@OneToMany(cascade = CascadeType.ALL, mappedBy = “nota”)
public Collection<ItemNota> getItensNota() {
return itensNota;
}

public void setItensNota(Collection<ItemNota> itensNota) {
this.itensNota = itensNota;
}
}

Em seguida, tempos a classe NotaPk que representa uma chave composta para a entidade Nota. Precisamos desta classe extra, pois para identificar a entidade nota, temos 3 campos diferentes (número, tipo e data) diferente da classe Produto que tem somente um campo (id).

[NotaPk.java]

package com.wordpress.ericogr.entities;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Embeddable
public class NotaPk implements Serializable {
private static final long serialVersionUID = -6450890424150718733L;

private int numero1;
private int tipo;
private Date data;

public NotaPk() {
}

public NotaPk(int numero, int tipo, Date data) {
setNumero(numero);
setTipo(tipo);
setData(data);
}

@Column(name = “numero”)
public int getNumero() {
return numero1;
}

public void setNumero(int numero) {
this.numero1 = numero;
}

@Column(name = “tipo”)
public int getTipo() {
return tipo;
}

public void setTipo(int tipo) {
this.tipo = tipo;
}

@Temporal(value = TemporalType.DATE)
@Column(name = “data”)
public Date getData() {
return data;
}

public void setData(Date data) {
this.data = data;
}

@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof NotaPk)) {
return false;
}

NotaPk pk = (NotaPk)obj;

return (pk.getData().equals(this.getData()) &&
pk.getNumero() == this.getNumero() &&
pk.getTipo() == this.getTipo());
}

@Override
public int hashCode() {
int ret = 0;

ret =
getNumero() ^
getTipo() ^
(getData() != null ? getData().hashCode() : 0);

return ret;
}
}

Agora os itens da nota fiscal. Os itens são compostos por um id que o identifica unicamente, quantidade, produto e nota fiscal a que pertence.

[ItemNota.java]

package com.wordpress.ericogr.entities;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

@Entity
@Table(name = “item_nota”)
public class ItemNota implements Serializable {
private int id;
private int quantidade;
private Produto produto;
private Nota nota;

public ItemNota() {
}

public ItemNota(int id, int quantidade, Produto produto) {
setId(id);
setQuantidade(quantidade);
setProduto(produto);
}

@Id
public int getId() {
return id;
}

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

@Column(name = “quantidade”)
public int getQuantidade() {
return quantidade;
}

public void setQuantidade(int quantidade) {
this.quantidade = quantidade;
}

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public Produto getProduto() {
return produto;
}

public void setProduto(Produto produto) {
this.produto = produto;
}

@ManyToOne
public Nota getNota() {
return nota;
}

public void setNota(Nota nota) {
this.nota = nota;
}
}

Produtos da nota fiscal: possui um id que o identifica, nome, peso, imagem (onde podemos gravar a figura do produto) e uma lista de fornecedores.

[Produto.java]

package com.wordpress.ericogr.entities;

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

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = “produto”)
public class Produto implements Serializable {
private int id;
private String nome;
private float peso;
private byte[] imagem;
private List<Fornecedor> fornecedores = new ArrayList<Fornecedor>();

public Produto() {
}

public Produto(int id, String nome, float peso) {
setId(id);
setNome(nome);
setPeso(peso);
}

@Id
@Column(name = “id”)
public int getId() {
return id;
}

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

@Column(name = “nome”)
public String getNome() {
return nome;
}

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

@Column(name = “peso”)
public float getPeso() {
return peso;
}

public void setPeso(float peso) {
this.peso = peso;
}

@Column(name = “imagem”)
public byte[] getImagem() {
return imagem;
}

public void setImagem(byte[] imagem) {
this.imagem = imagem;
}

@ManyToMany(cascade = CascadeType.ALL)
public List<Fornecedor> getFornecedores() {
return fornecedores;
}

public void setFornecedores(List<Fornecedor> fornecedores) {
this.fornecedores = fornecedores;
}
}

O Cadastro de fornecedores é composto por um identificador (id), nome, endereço e produtos que fornece.

[Fornecedor.java]

package com.wordpress.ericogr.entities;

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

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = “fornecedor”)
public class Fornecedor implements Serializable {
private int id;
private String nome;
private String endereco;
private List<Produto> produtos = new ArrayList<Produto>();

public Fornecedor() {
}

public Fornecedor(int id, String nome, String endereco) {
setId(id);
setNome(nome);
setEndereco(endereco);
}

@Id
public int getId() {
return id;
}

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

public String getNome() {
return nome;
}

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

public String getEndereco() {
return endereco;
}

public void setEndereco(String endereco) {
this.endereco = endereco;
}

@ManyToMany(cascade = CascadeType.ALL)
public List<Produto> getProdutos() {
return produtos;
}

public void setProdutos(List<Produto> produtos) {
this.produtos = produtos;
}
}

Finalmente a classe principal para testarmos o funcionamento das entidades que mapeamos. Criamos uma nota com itens, produtos e fornecedores e em seguida efetuamos uma consulta.

[Main.java]

package com.wordpress.ericogr;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import com.wordpress.ericogr.entities.Fornecedor;
import com.wordpress.ericogr.entities.ItemNota;
import com.wordpress.ericogr.entities.Nota;
import com.wordpress.ericogr.entities.NotaPk;
import com.wordpress.ericogr.entities.Produto;

public class Main {

public static void main(String[] args) {
new Main();
}

@SuppressWarnings(“unchecked”)
public Main() {
EntityManagerFactory emf;
EntityManager em;

Nota nota1;
NotaPk notaPk1;
ItemNota itemNota1, itemNota2;
Produto produto1, produto2;
Fornecedor fornecedor1, fornecedor2;

Query q;

emf = Persistence.createEntityManagerFactory(“testeJpaPU”);
em = emf.createEntityManager();

//produto
produto1 = new Produto(1, “Cimento”, 5000);
produto2 = new Produto(2, “Piso 12×10”, 475.3f);

//fornecedor
fornecedor1 = new Fornecedor(1, “JaxPCimentos”, “Rua Galeteri Blota, 123”);
fornecedor2 = new Fornecedor(2, “Kermit Ltda”, “Av Blogus, 987”);

//fornecedor x produto
fornecedor1.getProdutos().add(produto1);
fornecedor2.getProdutos().add(produto1);
fornecedor2.getProdutos().add(produto2);

//produto x fornecedor
produto1.getFornecedores().add(fornecedor1);
produto2.getFornecedores().add(fornecedor1);
produto2.getFornecedores().add(fornecedor2);

//notaPk
notaPk1 = new NotaPk(1, 2, new Date());

//item Nota
itemNota1 = new ItemNota(1, 120, produto1);
itemNota2 = new ItemNota(2, 151, produto2);

//nota
nota1 = new Nota(notaPk1);
nota1.setDescricao(“teste de nota”);
nota1.getItensNota().add(itemNota1);
nota1.getItensNota().add(itemNota2);

//item nota x nota
itemNota1.setNota(nota1);
itemNota2.setNota(nota1);

em.getTransaction().begin();
em.persist(nota1);
em.getTransaction().commit();

q = em.createQuery(“select n from Nota n where n.notaPk.numero = 1”);
List<Nota> ns = (List<Nota>)q.getResultList();

for (Nota n1 : ns) {
System.out.println(“[Nota]”);
System.out.println(“Nota nr: ” + n1.getNotaPk().getNumero() + “\n” +
“Nota tp: ” + n1.getNotaPk().getTipo() + “\n” +
“Nota dt: ” + n1.getNotaPk().getData() + “\n” +
“Nota ds: ” + n1.getDescricao() + “\n”);
for (ItemNota in : n1.getItensNota()) {
System.out.println(“[Itens]”);
System.out.println(“Item…: ” + in.getId() + “\n” +
“Prod…: ” + in.getProduto().getNome() + “\n” +
“Quant..: ” + in.getQuantidade() + “\n” +
“Ref Not: ” + in.getNota().getNotaPk().getNumero() + “\n”);
for (Fornecedor f : in.getProduto().getFornecedores()) {
System.out.println(“[Fornecedores]”);
System.out.println(“Fornecedor: ” + f.getId() + “\n” +
“Nome…..: ” + f.getNome() + “\n” );
}
}
}

em.close();
}
}

Com este exemplo podemos observar como é fácil mapear os objetos para serem persistidos no banco de dados. Observamos o funcionamento das anotações @OneToOne, @OneToMany, @ManyToOne e @ManyToMany através de um exemplo simples que pode ser incrementado para um caso real.

5 Respostas to “Criando relacionamentos com JPA”

  1. Gustavo Magni Bueno said

    Massa!!!!!!

  2. Moacir said

    Embora os campos das tabelas pareçam obvios, não é possivel executar seu exemplo. Poderia disponibilizar o sql das tabelas?

  3. LUIZ HENRIQUE DAL POZZO said

    Muito bom me ajudou muito.

  4. Eduaro Raiol said

    Olá amigo, muito bom e didático seu exemplo, so gostaria de saber como persistir o relacionamento fornecedor/produto? tipo salvo o fornecerdor normalmente, depois salvo o produto e então como seria para salvar o fornecedor-produto?? novo com jpa.

    Desde já agradeço!

  5. asda said

    Sem o SQL das tabelas realmente a didatica vai pro espaço concordo com o amigo Moacir!!

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

 
%d blogueiros gostam disto: