Os quatro tipos de cardinalidade

Um-para-Um (OneToOne)

Este relacionamento informa que há apenas um registro da entidade relacionado com um registro de outra entidade.

Exemplo de relacionamento Um-para-Um unidirecional:

Script do banco de dados:

CREATE TABLE Mensagem (
  id number(5) NOT NULL PRIMARY_KEY,
  assunto varchar2(200) NOT NULL,
  dataEnvio date NOT NULL,
  mensagemcorpo_id number(5)
);

CREATE TABLE MensagemCorpo (
  id number(5) NOT NULL PRIMARY KEY,
  descricao varchar2(200)
);

Modelo UML:

Exemplo Um-para-Um

Neste exemplo definimos que uma Mensagm possui uma MensagemCorpo, então desta forma a Mensagem sabe qual é seu MensagemCorpo, mas o contrario não existe, a MensagemCorpo não tem a necessidade de conhecer qual a Mensagem está associado a ele, ou seja, temos um relacionamento unidirecional.

Primeiramente podemos mostrar apenas uma listagem de Mensagens, mas não tem necessidade por enquanto de mostrar o conteúdo de todas as mensagens e depois caso eu queira ler o conteúdo da mensagem podemos através dela chegar até seu corpo utilizando o atributo do tipo MensagemCorpo.

Código fonte das classes com o relacionamento:

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * Classe utilizada para representar uma Mensagem.
 */
@Entity
public class Mensagem implements Serializable {
  private static final long serialVersionUID 
    = 1912492882356572322L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String assunto;

  @Temporal(TemporalType.DATE)
  private Date dataEnvio;

  @OneToOne(cascade=CascadeType.ALL)
  private MensagemCorpo mensagemCorpo;

  public String getAssunto() { return assunto; }
  public void setAssunto(String assunto) {
    this.assunto = assunto;
  }

  public Date getDataEnvio() { return dataEnvio; }
  public void setDataEnvio(Date dataEnvio) {
    this.dataEnvio = dataEnvio;
  }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public MensagemCorpo getMensagemCorpo() {
    return mensagemCorpo;
  }
  public void setMensagemCorpo(MensagemCorpo mensagemCorpo) {
    this.mensagemCorpo = mensagemCorpo;
  }
}

Na classe Mensagem utilizamos a anotação javax.persistence.OneToOne para definir o relacionamento de um-para-um entre as classes Mensagem e MensagemCorpo.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Classe utilizada para representar o corpo de uma
 * mensagem.
 */
@Entity
public class MensagemCorpo implements Serializable {
  private static final long serialVersionUID 
    = 986589124772488369L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String descricao;

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

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }
}

A classe MensagemCorpo é uma entidade normal que não conhece a classe Mensagem.

Note que não precisamos criar nenhuma referencia para informar que o atributo mensagemCorpo da classe Mensagem referencia a coluna mensagemcorpo_id da tabela Mensagem.

O JPA possui alguns padrões para facilitar o mapeamento entre a classe Java e a tabela do banco de dados, quando criamos uma coluna de chave estrangeira seguindo o padrão nometabela_chaveprimaria, o mapeamento é feito automaticamente pelo JPA, ou seja, o atributo MensagemCorpo mensagemCorpo é automaticamente associado com a coluna mensagemcorpo_id.

javax.persistence.OneToOne

Esta anotação define uma associação com outra entidade que tenha a multiplicidade de um-para-um. A tabela a seguir mostra as propriedades da anotação @OneToOne.

Propriedade Descrição
cascade As operações que precisam ser refletidas no alvo da associação.
fetch Informa se o alvo da associação precisa ser obtido apenas quando for necessário ou se sempre deve trazer.
mappedBy Informa o atributo que é dono do relacionamento.
optional Informa se a associação é opcional.
targetEntity A classe entity que é alvo da associação.

Quando precisamos especificar um mapeamento que não é padrão do JPA, podemos utilizar a anotação javax.persistence.JoinColumn, por exemplo se a tabela Mensagem e MensagemCorpo fossem:

CREATE TABLE Mensagem (
  id number(5) NOT NULL PRIMARY KEY,
  assunto varchar2(200),
  dataEnvio date,
  ID_MENSAGEMCORPO number(5)
);

CREATE TABLE MensagemCorpo (
  MC_ID number(5) NOT NULL PRIMARY_KEY,
  descricao varchar2(200)
);

Poderíamos utilizar o JoinColumn para criar a associação:

@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="ID_MENSAGEMCORPO", referencedColumnName="MC_ID")
private MensagemCorpo mensagemCorpo;

javax.persistence.JoinColumn

Esta anotação é utilizada para especificar a coluna utilizada na associação com outra entity. A tabela a seguir apresenta as propriedades da anotação @JoinColumn.

Propriedade Descrição
columnDefinition Definição do tipo da coluna.
insertable Informa se a coluna é incluída no SQL de INSERT.
name Informa o nome da coluna de chave estrangeira.
nullable Informa se a coluna pode ser null.
referencedColumnName Nome da coluna que é referenciada pela coluna da chave estrangeira.
table Nome da tabela que contém a coluna.
unique Informa se a propriedade é chave única.
updatable Informa se a coluna é incluída no SQL de UPDATE.

Um-para-Muitos (OneToMany)

Este relacionamento informa que o registro de uma entidade está relacionado com vários registros de outra entidade.

Exemplo de relacionamento Um-para-Muitos unidirecional:

Script do banco de dados:

CREATE TABLE Aula (
  id number(5) NOT NULL PRIMARY KEY,
  titulo varchar2(45) NOT NULL,
  data date NOT NULL
);

CREATE TABLE Tarefa (
  id number(5) NOT NULL PRIMARY KEY,
  titulo varchar2(45) NOT NULL,
  descricao varchar2(45) NOT NULL,
  aula_id number(5)
);

Modelo UML:

Exemplo Um-para-Muitos

Neste exemplo definimos que uma Aula possui uma lista de Tarefa, portanto a aula pode não ter tarefa, pode ter apenas uma tarefa ou pode ter varias tarefas, uma Tarefa não precisa saber de qual Aula ela está associada, portanto temos um relacionamento unidirecional.

Código fonte das classes com o relacionamento:

Na classe Aula utilizamos a anotação javax.persistence.OneToMany no atributo tarefas, para informar que uma Aula está associada com várias tarefas.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * Classe utilizada para representar uma aula.
 */
@Entity
public class Aula implements Serializable {
  private static final long serialVersionUID 
    = -6745032908099856302L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String titulo;

  @Temporal(TemporalType.DATE)
  private Date data;

  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name="aula_id")
  private List<Tarefa> tarefas;

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

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public String getTitulo() { return titulo; }
  public void setTitulo(String titulo) {
    this.titulo = titulo;
  }

  public List<Tarefa> getTarefas() { return tarefas; }
  public void setTarefas(List<Tarefa> tarefas) {
    this.tarefas = tarefas;
  }
}

javax.persistence.OneToMany

Esta anotação define uma associação com outra entidade que tenha a multiplicidade de um-para-muitos.

Propriedade Descrição
cascade As operações que precisam ser refletidas no alvo da associação.
fetch Informa se o alvo da associação precisa ser obtido apenas quando for necessário ou se sempre deve trazer.
mappedBy Informa o atributo que é dono do relacionamento.
targetEntity A classe entity que é alvo da associação.

A classe Tarefa é uma entidade normal que não conhece a classe Aula.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
 * Classe utilizada para representar as tarefas 
 * aplicadas em uma aula.
 */
@Entity
public class Tarefa implements Serializable {
  private static final long serialVersionUID = 2952630017127173988L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String titulo;
  private String descricao;

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

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public String getTitulo() { return titulo; }
  public void setTitulo(String titulo) {
    this.titulo = titulo;
  }
}

Muitos-para-Um (ManyToOne)

Este relacionamento informa que existem muitos registros de uma entidade associados a um registro de outra entidade.

Exemplo de relacionamento Um-para-Muitos e Muitos-para-Um bidirecional:

Script do banco de dados:

CREATE TABLE Pessoa (
  id number(5) NOT NULL PRIMARY KEY,
  nome varchar2(200) NOT NULL,
  cpf varchar2(11) NOT NULL
);

CREATE TABLE Telefone (
  id number(5) NOT NULL PRIMARY KEY,
  tipo varchar2(200) NOT NULL,
  numero number(8) NOT NULL,
  pessoa_id number(5)
);

Modelo UML:

Exemplo Muitos-para-Um

Neste exemplo definimos que uma Pessoa possui uma lista de Telefones e um Telefone está associado a uma Pessoa, portanto temos um relacionamento bidirecional.

Código fonte das classes com o relacionamento:

Na entidade Pessoa definimos que uma pessoa possui vários telefones através do atributo List<Telefone> telefones e adicionamos a anotação javax.persistence.OneToMany para informar que o relacionamento de Pessoa para Telefone é de Um-para-Muitos, note que nesta anotação definimos a propriedade mappedBy como "pessoa" que é para informar que o atributo com o nome pessoa na entity Telefone que é dona do relacionamento.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

/**
 * Classe utilizada para representar uma Pessoa.
 */
@Entity
public class Pessoa implements Serializable {
  private static final long serialVersionUID 
    = -1905907502453138175L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String nome;
  private String cpf;
  @OneToMany(mappedBy="pessoa", cascade=CascadeType.ALL)
  private List<Telefone> telefones;

  public String getCpf() { return cpf; }
  public void setCpf(String cpf) { this.cpf = cpf; }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

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

  public List<Telefone> getTelefones() { return telefones; }
  public void setTelefones(List<Telefone> telefones) {
    this.telefones = telefones;
  }
}

Na entidade Telefone definimos o atributo Pessoa pessoa e adicionamos a anotação javax.persistence.ManyToOne para definir que o relacionamento de Telefone para Pessoa é de Muitos-para-Um.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
 * Classe utilizada para representar um Telefone.
 */
@Entity
public class Telefone implements Serializable {
  private static final long serialVersionUID 
    = 7526502149208345058L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String tipo;
  private Integer numero;
  @ManyToOne
  private Pessoa pessoa;

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public Integer getNumero() { return numero; }
  public void setNumero(Integer numero) {
    this.numero = numero;
  }

  public Pessoa getPessoa() { return pessoa; }
  public void setPessoa(Pessoa pessoa) {
    this.pessoa = pessoa;
  }

  public String getTipo() { return tipo; }
  public void setTipo(String tipo) { this.tipo = tipo; }
}

javax.persistence.ManyToOne

Esta anotação define uma associação com outra entidade que tenha a multiplicidade de muitos-para-um.

Propriedade Descrição
cascade As operações que precisam ser refletidas no alvo da associação.
fetch Informa se o alvo da associação precisa ser obtido apenas quando for necessário ou se sempre deve trazer.
optional Informa se a associação é opcional.
targetEntity A classe entity que é alvo da associação.

Também podemos adicionar uma tabela para realizar o relacionamento unidirecional de um-para-muitos e o relacionamento muitos-para-muitos, normalmente utilizamos está alternativa como uma forma de normalizar os dados evitando duplicar o conteúdo dos registros.

Nesse exemplo queremos utilizar a entidade Telefone com as entidades Pessoa e Aluno, dessa forma Pessoa possui uma lista de Telefones e Aluno possui uma lista de Telefones, mas o telefone não sabe para quem ele está associado. Este tipo de relacionamento é unidirecional de um-para-muitos.

Exemplo Associação Um-para-Muitos

Na base de dados iremos criar as tabelas Pessoa, Telefone e Aluno, também iremos criar duas tabelas de associação chamadas Pessoa_Telefone e Aluno_Telefone:

CREATE TABLE Pessoa (
  id number(5) NOT NULL PRIMARY KEY,
  nome varchar2(200) NOT NULL,
  cpf varchar2(11) NOT NULL
);

CREATE TABLE Aluno (
  id number(5) NOT NULL PRIMARY_KEY,
  nome varchar2(200) NOT NULL,
  matricula number(5) NOT NULL
);

CREATE TABLE Telefone (
  id number(5) NOT NULL PRIMARY KEY,
  tipo varchar2(200) NOT NULL,
  numero number(5) NOT NULL
);

CREATE TABLE Pessoa_Telefone (
  pessoa_id number(5),
  telefone_id number(5)
);

CREATE TABLE Aluno_Telefone (
  aluno_id number(5),
  telefone_id number(5)
);

Na entidade Pessoa definimos que uma pessoa possui vários telefones através do atributo List<Telefone> telefones e adicionamos a anotação javax.persistence.OneToMany para informar que o relacionamento de Pessoa para Telefone é de Um-para-Muitos.

Para informar que vamos utilizar a tabela PESSOA_TELEFONE para realizar a associação entre as tabelas PESSOA e TELEFONE utilizamos a anotação javax.persistence.JoinTable.

Para informar que a coluna PESSOA_ID da tabela PESSOA_TELEFONE é a coluna chave estrangeira para a tabela PESSOA e para informar que a coluna TELEFONE_ID da tabela PESSOA_TELEFONE é a chave estrangeira para a tabela TELEFONE utilizamos a anotação javax.persistence.JoinColumn.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;

/**
 * Classe utilizada para representar uma Pessoa.
 */
@Entity
public class Pessoa implements Serializable {
  private static final long serialVersionUID 
    = -1905907502453138175L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String nome;
  private String cpf;
  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinTable(name="PESSOA_TELEFONE",
    joinColumns={@JoinColumn(name = "PESSOA_ID")},
    inverseJoinColumns={@JoinColumn(name = "TELEFONE_ID")})
  private List<Telefone> telefones;

  public String getCpf() { return cpf; }
  public void setCpf(String cpf) { this.cpf = cpf; }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

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

  public List<Telefone> getTelefones() { return telefones; }
  public void setTelefones(List<Telefone> telefones) {
    this.telefones = telefones;
  }
}

javax.persistence.JoinTable

Esta anotação é utilizada para definir uma tabela que será utilizada na associação de um-para-muitos ou de muitos-para-muitos.

Propriedade Descrição
catalog O catalogo da tabela.
inverseJoinColumns Chave estrangeira para realizar a associação com a tabela que não é dona do relacionamento.
joinColumns Chave estrangeira para realizar a associação com a tabela que é dona do relacionamento.
name Nome da tabela de associação.
schema Esquema da tabela.
uniqueConstraints Regras que podem ser adicionadas na tabela.

Na entidade Aluno definimos que um aluno possui vários telefones através do atributo List<Telefone> telefones e adicionamos a anotação javax.persistence.OneToMany para informar que o relacionamento de Aluno para Telefone é de Um-para-Muitos.

Para informar que vamos utilizar a tabela ALUNO_TELEFONE para realizar a associação entre as tabelas ALUNO e TELEFONE utilizamos a anotação javax.persistence.JoinTable.

Para informar que a coluna ALUNO_ID da tabela ALUNO_TELEFONE é a coluna chave estrangeira para a tabela ALUNO e para informar que a coluna TELEFONE_ID da tabela ALUNO_TELEFONE é a chave estrangeira para a tabela TELEFONE utilizamos a anotação javax.persistence.JoinColumn.

package pbc.jpa.exemplo.modelo;

import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;

/**
 * Classe utilizada para representar uma entidade Aluno.
 */
@Entity
public class Aluno {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String nome;
  private Long matricula;
  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinTable(name="ALUNO_TELEFONE",
    joinColumns={@JoinColumn(name = "ALUNO_ID")},
    inverseJoinColumns={@JoinColumn(name = "TELEFONE_ID")})
  private List<Telefone> telefones;

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public Long getMatricula() { return matricula; }
  public void setMatricula(Long matricula) {
    this.matricula = matricula;
  }

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

  public List<Telefone> getTelefones() { return telefones; }
  public void setTelefones(List<Telefone> telefones) {
    this.telefones = telefones;
  }
}

Agora vamos declarar a entidade Telefone, note que esta entidade não conhece as associações que são criadas para ela.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * Classe utilizada para representar um Telefone.
 */
@Entity
public class Telefone implements Serializable {
  private static final long serialVersionUID 
    = 7526502149208345058L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String tipo;
  private Integer numero;

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

  public Integer getNumero() { return numero; }
  public void setNumero(Integer numero) {
    this.numero = numero;
  }

  public String getTipo() { return tipo; }
  public void setTipo(String tipo) { this.tipo = tipo; }
}

Para testar o cadastro de Aluno e Telefone vamos criar a classe AlunoDAO para salvar, alterar, consultar por id e apagar os registro do aluno e telefone.

package pbc.jpa.exemplo.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import pbc.jpa.exemplo.modelo.Aluno;

/**
 * Classe DAO para manipular as informações do
 * Aluno no banco de dados.
 */
public class AlunoDAO {
  private EntityManager getEntityManager() {
    EntityManagerFactory factory = null;
    EntityManager entityManager = null;
    try {
      //Obtem o factory a partir da unidade de persistência.
      factory = Persistence.createEntityManagerFactory
        ("UnidadeDePersistencia");
      //Cria um entity manager.
      entityManager = factory.createEntityManager();
    } finally {
      factory.close();
    }
    return entityManager;
  }

  public Aluno consultarPorId(Long id) {
    EntityManager entityManager = getEntityManager();
    Aluno aluno = null;
    try {
      aluno = entityManager.find(Aluno.class, id);
    } finally {
      entityManager.close();
    }
    return aluno;
  }

  public Aluno salvar(Aluno aluno) {
    EntityManager entityManager = getEntityManager();
    try {
      // Inicia uma transação com o banco de dados.
      entityManager.getTransaction().begin();
      System.out.println("Salvando as informações do aluno.");
      /* Verifica se o aluno ainda não está salvo no 
        banco de dados. */
      if(aluno.getId() == null) {
        entityManager.persist(aluno);
      } else {
        aluno = entityManager.merge(aluno);
      }
      // Finaliza a transação.
      entityManager.getTransaction().commit();
    } catch(Exception ex) {
      entityManager.getTransaction().rollback();
    } finally {
      entityManager.close();
    }
    // Retorna o aluno salvo.
    return aluno;
  }

  public void apagar(Long id) {
    EntityManager entityManager = getEntityManager();
    try {
      // Inicia uma transação com o banco de dados.
      entityManager.getTransaction().begin();
      // Consulta o aluno na base de dados através do seu ID.
      Aluno aluno = entityManager.find(Aluno.class, id);
      System.out.println("Excluindo o aluno: " 
        + aluno.getNome());

      // Remove o aluno da base de dados.
      entityManager.remove(aluno);
      // Finaliza a transação.
      entityManager.getTransaction().commit();
    } catch(Exception ex) {
      entityManager.getTransaction().rollback();
    } finally {
      entityManager.close();
    }
  }
}

Vamos criar a classe AlunoDAOTeste que utiliza a classe AlunoDAO para salvar, alterar, consultar por id e apagar os registros de aluno e telefone:

package pbc.jpa.exemplo.dao;

import java.util.ArrayList;
import java.util.List;
import pbc.jpa.exemplo.modelo.Aluno;
import pbc.jpa.exemplo.modelo.Telefone;

/**
 * Classe utilizada para testar as operações do 
 * banco de dados referente ao Aluno.
 */
public class AlunoDAOTeste {
  public static void main(String[] args) {
    AlunoDAO dao = new AlunoDAO();

    //Cria uma aluno.
    Aluno aluno = new Aluno();
    aluno.setNome("Rafael");
    aluno.setMatricula(123456L);

    //Cria o telefone residencial do aluno.
    Telefone telefone = new Telefone();
    telefone.setTipo("RES");
    telefone.setNumero(12345678);
    //Cria o telefone celular do aluno.
    Telefone telefone2 = new Telefone();
    telefone2.setTipo("CEL");
    telefone2.setNumero(87654321);

    //Cria uma lista de telefones e guarda dentro do aluno.
    List<Telefone> telefones = new ArrayList<Telefone>();
    telefones.add(telefone);
    telefones.add(telefone2);
    aluno.setTelefones(telefones);

    System.out.println("Salva as informações do aluno.");
    aluno = dao.salvar(aluno);

    System.out.println("Consulta o aluno que foi salvo.");
    Aluno alunoConsultado = dao.consultarPorId(aluno.getId());
    System.out.println(aluno.getNome());
    for(Telefone tel : aluno.getTelefones()) {
      System.out.println(tel.getTipo() + " - " 
        + tel.getNumero());
    }

    //Cria o telefone comercial do aluno.
    Telefone telefone3 = new Telefone();
    telefone3.setTipo("COM");
    telefone3.setNumero(55554444);
    //Adiciona o novo telefone a lista de telefone do aluno.
    alunoConsultado.getTelefones().add(telefone3);

    System.out.println("Atualiza as informações do aluno.");
    alunoConsultado = dao.salvar(alunoConsultado);
    System.out.println(alunoConsultado.getNome());
    for(Telefone tel : alunoConsultado.getTelefones()) {
      System.out.println(tel.getTipo() + " - " 
        + tel.getNumero());
    }

    System.out.println("Apaga o registro do aluno.");
    dao.apagar(alunoConsultado.getId());
  }
}

Quando executamos a classe AlunoDAOTeste temos a seguinte saída no console:

Salva as informações do aluno:

Hibernate: insert into Aluno (matricula, nome) values (?, ?)
Hibernate: insert into Telefone (numero, tipo) values (?, ?)
Hibernate: insert into Telefone (numero, tipo) values (?, ?)
Hibernate: insert into ALUNO_TELEFONE (ALUNO_ID, TELEFONE_ID)
values (?, ?)
Hibernate: insert into ALUNO_TELEFONE (ALUNO_ID, TELEFONE_ID)
values (?, ?)

Consulta o aluno que foi salvo:

Hibernate: select aluno0_.id as id21_1_, aluno0_.matricula as
matricula21_1_, aluno0_.nome as nome21_1_, telefones1_.ALUNO_ID
as ALUNO1_3_, telefone2_.id as TELEFONE2_3_, telefone2_.id as
id18_0_, telefone2_.numero as numero18_0_, telefone2_.tipo as
tipo18_0_ from Aluno aluno0_ left outer join ALUNO_TELEFONE
telefones1_ on aluno0_.id=telefones1_.ALUNO_ID left outer join
Telefone telefone2_ on telefones1_.TELEFONE_ID=telefone2_.id 
where aluno0_.id=?Rafael
RES - 12345678
CEL - 87654321

Atualiza as informações do aluno:

Hibernate: select aluno0_.id as id38_1_, aluno0_.matricula as
matricula38_1_, aluno0_.nome as nome38_1_, telefones1_.ALUNO_ID
as ALUNO1_3_, telefone2_.id as TELEFONE2_3_, telefone2_.id as
id35_0_, telefone2_.numero as numero35_0_, telefone2_.tipo as
tipo35_0_ from Aluno aluno0_ left outer join ALUNO_TELEFONE
telefones1_ on aluno0_.id=telefones1_.ALUNO_ID left outer join
Telefone telefone2_ on telefones1_.TELEFONE_ID=telefone2_.id
where aluno0_.id=?
Hibernate: insert into Telefone (numero, tipo) values (?, ?)
Hibernate: delete from ALUNO_TELEFONE where ALUNO_ID=?
Hibernate: insert into ALUNO_TELEFONE (ALUNO_ID, TELEFONE_ID)
values (?, ?)
Hibernate: insert into ALUNO_TELEFONE (ALUNO_ID, TELEFONE_ID)
values (?, ?)
Hibernate: insert into ALUNO_TELEFONE (ALUNO_ID, TELEFONE_ID)
values (?, ?)
Rafael
RES - 12345678
CEL - 87654321
COM - 55554444

Apaga o registro do aluno:

Hibernate: select aluno0_.id as id55_1_, aluno0_.matricula as
matricula55_1_, aluno0_.nome as nome55_1_, telefones1_.ALUNO_ID
as ALUNO1_3_, telefone2_.id as TELEFONE2_3_, telefone2_.id as
id52_0_, telefone2_.numero as numero52_0_, telefone2_.tipo as
tipo52_0_ from Aluno aluno0_ left outer join ALUNO_TELEFONE
telefones1_ on aluno0_.id=telefones1_.ALUNO_ID left outer join
Telefone telefone2_ on telefones1_.TELEFONE_ID=telefone2_.id
where aluno0_.id=?
Hibernate: delete from ALUNO_TELEFONE where ALUNO_ID=?
Hibernate: delete from Telefone where id=?
Hibernate: delete from Telefone where id=?
Hibernate: delete from Telefone where id=?
Hibernate: delete from Aluno where id=?

Muitos-para-Muitos (ManyToMany)

Este relacionamento informa que muitos registros de uma entidade estão relacionados com muitos registros de outra entidade:

Script do banco de dados:

CREATE TABLE Projeto (
  id number(5) NOT NULL PRIMARY_KEY,
  nome varchar2(200) NOT NULL
);

CREATE TABLE Funcionario (
  id number(5) NOT NULL PRIMARY_KEY,
  nome varchar2(200) NOT NULL
);

CREATE TABLE Projeto_Funcionario (
  projeto_id number(5),
  funcionario_id number(5)
);

Note que nesse caso precisamos utilizar uma tabela intermediária entre Projeto e Funcionario, para evitar duplicar dados (normalização) desnecessários no banco de dados. Através da tabela Projeto_Funcionario criamos o relacionamento entre Projeto e Funcionario.

Modelo UML:

Exemplo Muitos-para-Muitos

Neste exemplo definimos que um Projeto tem vários funcionários, e um Funcionario participa de vários projetos, portanto temos um relacionamento bidirecional de muitos-para-muitos.

Código fonte das classes com o relacionamento:

A entidade Projeto possui um relacionamento de muitos-para-muitos com a entidade Funcionario, para definir esta associação utilizamos a anotação javax.persistence.ManyToMany, note que utilizamos a propriedade mappedBy da anotação ManyToMany para informar que o Projeto é o dono do relacionamento.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

/**
 * Classe utilizada para representar um projeto.
 */
@Entity
public class Projeto implements Serializable {
  private static final long serialVersionUID 
    = 1081869386060246794L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String nome;
  @ManyToMany(mappedBy="projetos", cascade=CascadeType.ALL)
  private List<Funcionario> desenvolvedores;

  public List<Funcionario> getDesenvolvedores() {
    return desenvolvedores;
  }
  public void setDesenvolvedores(List<Funcionario>
    desenvolvedores) {
    this.desenvolvedores = desenvolvedores;
  }

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

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

javax.persistence.ManyToMany

Esta anotação define uma associação com outra entidade que tenha a multiplicidade de muitos-para-muitos.

Propriedade Descrição
cascade As operações que precisam ser refletidas no alvo da associação.
fetch Informa se o alvo da associação precisa ser obtido apenas quando for necessário ou se sempre deve trazer.
mappedBy Informa o atributo que é dono do relacionamento.
targetEntity A classe entity que é alvo da associação.

A entidade Funcionario possui um relacionamento de muitos-para-muitos com a entidade Projeto, para definir esta associação utilizamos a anotação javax.persistence.ManyToMany.

Para informar que vamos utilizar a tabela PROJETO_FUNCIONARIO para realizar a associação entre PROJETO e FUNCIONARIO utilizamos a anotação javax.persistence.JoinTable.

Para informar que a coluna PROJETO_ID da tabela PROJETO_FUNCIONARIO é a coluna chave estrangeira para a tabela PROJETO e para informar que a coluna FUNCIONARIO_ID da tabela PROJETO_FUNCIONARIO é a chave estrangeira para a tabela FUNCIONARIO utilizamos a anotação javax.persistence.JoinColumn.

package pbc.jpa.exemplo.modelo;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

/**
 * Classe utilizada para representar um Funcionário.
 */
@Entity
public class Funcionario implements Serializable {
  private static final long serialVersionUID 
    = -9109414221418128481L;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  private String nome;
  @ManyToMany(cascade = CascadeType.ALL)
  @JoinTable(name="PROJETO_FUNCIONARIO",
    joinColumns={@JoinColumn(name="PROJETO_ID")},
    inverseJoinColumns={@JoinColumn(name="FUNCIONARIO_ID")})
  private List<Projeto> projetos;

  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }

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

  public List<Projeto> getProjetos() { return projetos; }
  public void setProjetos(List<Projeto> projetos) {
    this.projetos = projetos;
  }
}

results matching ""

    No results matching ""