Páginas

terça-feira, 27 de agosto de 2013

Mapeamento de entidade com Hibernate


Olá tudo bem ?

Nesse post vou falar sobre mapeamento de entidades com hibernate.

Primeiramente crie um projeto Dynamic Web Project na IDE, adicione os jar do hibernate, tambem nao esqueça de adicionar o jar do banco de dados.

Configure o arquivo persistence.xml, para adicionar ao seu projeto (alt + enter) em cima do projeto > Project Facets > marque a opção JPA > Aplly > OK.

Crie uma database mapeamento

persistence.xml



  
  
   
   
   
   
   
   
   
  
 


Verifique o usuario e a senha do seu banco se corresponde com a mesma utilizada.

1.1 OneToOne
1.2 OneToMany
1.3 ManyToOne
1.4 ManyToMany

Vamos começar com relacionamento OneToOne (Um para Um).

1.1 OneToOne

No relacionamento OneTone (Um para Um), irei fazer como exemplo um relacionamento entre País e Presidente se "em caixa" perfeitamente nessa condição, aonde um País pode ter apenas um Presidente e um Presidente só pode administrar um País.

1.1.1 Vamos criar uma classe chamada País dentro do package br.com.vejajava.entidades
@Entity
@Table(name="pais")
public class Pais {
 
 @Id
 @GeneratedValue
 private Long id;
 
 private String nome;
 
 private String capital;
 
 @OneToOne
 private Presidente presidente;
 
 
 @Column(name="lingua_oficial")
 private String linguaOficial;
 
 private String populacao;

         // getters e setters
}
Podemos ver que na nossa classe País temos a anotação @OneToOne isso faz com que o relacionamento entre Pais e Presidente aconteça no banco de dados.
Observe que o tipo de dado que é feita no relacionamento com Presidente é do tipo Presidente e não um tipo primitivo.

1.1.2 Vamos criar uma classe chamada Presidente dentro do package br.com.vejajava.entidades
@Entity
@Table(name="presidente")
public class Presidente {
 
 @Id
 @GeneratedValue
 private Long id;
 
 private String nome;
 
 @OneToOne
 private Pais pais;

         // getters e setters
Observe que temos o mesmo tipo referenciado na classe Presidente, com anotação @OneToOne isso faz com que o relacionamento entre Pais e Presidente aconteça no banco de dados.

Temos que definir qual classe mandará no relacionamento.

Para resolver esse problema temos um elemento chamado mappedBy que é um relacionamento bidirecional, significa que tanto na classe Pais como na classe Presidente podemos carregar-lás.
Lembrando que toda a classe que faz um relacionamento e tenha essa função (mappedBy) ela nao mandará no relacionamento.

O relacionamento na classe Presidente ficará assim:
@OneToOne(mappedBy= "presidente")
private Pais pais;

No exemplo feito teria a foreing key presidente_id na tabela Pais, para modificar o nome desse campo existe uma anotação chamada @JoinColumn.

Ex:
@JoinColumn(name="pres_id")


1.1.3 Vamos criar uma classe chamada TesteOneToOne dentro do package br.com.vejajava.principal para fazer o teste do nosso relacionamento.


public class TesteOneToOne {
 public static void main(String[] args) {
  
  EntityManagerFactory factory = Persistence.createEntityManagerFactory("Mapeamento");
  EntityManager manager = factory.createEntityManager();
  
  manager.getTransaction().begin();
  
  Presidente presidente = new Presidente();
  presidente.setNome("Dilma R");
  
  Pais pais = new Pais();
  pais.setNome("Brasil");
  pais.setCapital("Brasília");
  pais.setLinguaOficial("Português");
  pais.setPopulacao(193.946886);
  
  pais.setPresidente(presidente);
  
  manager.persist(pais);
  manager.persist(presidente);
  
  manager.getTransaction().commit();
  
  manager.close();
  factory.close();
 }
}

Podemos observa que criamos uma instancia de Presidente e Pais e passamos os valores para eles.
Observe que pais.setPresidente(presidente) ele pega o valor passado quando criamos um novo Presidente.
Nao podemos fazer o mesmo para Presidente pois quem manda no relacionamento é classe País.

Observe que temos que persistir os dois objetos
manager.persist(pais);
manager.persist(presidente);
Com o elemento (Cascade = CascadeType.PERSIST) na classe Pais so bastaria persist o objeto do tipo Pais.

Veja como ficaria o elemento Cascade.

@OneToOne(cascade = CascadeType.PERSIST)
private Presidente presidente;

Se tudo ocorrer bem no seu banco de dados vai ter os seguintes valores:

mysql> select * from pais;
+----+-----------+----------------+--------+------------+---------------+
| id | capital | lingua_oficial | nome | populacao | presidente_id |
+----+-----------+----------------+--------+------------+---------------+
| 1 | Brasília | Português | Brasil | 193.946886 | 1 |
+----+-----------+----------------+--------+------------+---------------+
mysql> select * from presidente;
+----+---------+
| id | nome |
+----+---------+
| 1 | Dilma R |
+----+---------+

1.2 OneToMany

No relacionamento OneToMany(Um para Muitos), irei fazer como exemplo um relacionamento entre Escola e Aluno se "em caixa" perfeitamente nessa condição, aonde uma Escola pode ter vários Alunos.

1.2.1 Vamos criar uma classe chamada Escola dentro do package br.com.vejajava.entidades

@Entity
@Table(name="escola")
public class Escola {
 
 @Id
 @GeneratedValue
 private Long id;
 
 private String nome;

        @OneToMany(cascade = CascadeType.PERSIST)
 private Collection alunos = new ArrayList();
 
       //getters e setters
}
Observe que na classe Escola só temos 2 atributos, coloquei apenas esses dois pra entender melhor o relacionamento.
Temos uma Coleção de Alunos seguido da anotação @OneToMany, (Um para Muitos) aonde uma Escola pode ter varios alunos, temos também o elemento cascade = CascadeType.PERSIST faz com que quando o objeto escola for persistido ele automaticamente persist todos os campos que está fazendo o relacionamento entre escola e aluno. Esse relacionamento so pode ser carregado na classe Escola pois nao é um relacionamento bidirecional, para que seja um relacionamento bidirecional seria necessário adicionar o mappedyBy no relacionamento @OneToMany.

1.2.2 Vamos criar uma classe chamada Aluno dentro do package br.com.vejajava.entidades

Nessa classe vamos aprofundar mais um pouco e entender a anotação @Embedded

@Entity
@Table(name="aluno")
public class Aluno {
 
 @Id
 @GeneratedValue
 private Long id;
 
 private String nome;
 
 @Embedded
 private Endereco endereco;
         
         //getters e setters
}
Observe que na classe Aluno temos a anotação @Embedded essa anotação faz com que eu possa criar uma classe com as informações do endereço do aluno, sem a necessidade de criar outra tabela. Ela pega todos os atributos da classe endereco que será criada e coloca dentro da propria tabela aluno, essa é uma maneira muito interessante para organização do seu sistema.
Criando uma classe para colocar todas as informações de endereço para organizar, caso houver que mudar algum campo que referencia o endereco do aluno só precisaria alterar a classe endereco;

1.2.3 Vamos criar uma classe chamada Endereco dentro do package br.com.vejajava.entidades

@Embeddable
public class Endereco {

 private String rua;
 
 private int numero;
 
 private String cep;
      
         //getters e setters
}
Observe que no lugar da anotação @Entity temos a anotação @Embeddable isso faz com que nao seja criado uma tabela endereco no banco de dados e todos os campos dessa classe será criado na tabela Aluno, veja também que não precisamos definir uma primary key para essa classe.

1.2.4 Vamos criar uma classe chamada TesteOneToMany dentro do package br.com.vejajava.principal para fazer o teste do nosso relacionamento.

public class TesteOneToMany {
 
 public static void main(String[] args) {
  
  EntityManagerFactory factory = Persistence.createEntityManagerFactory("Mapeamento");
  EntityManager manager = factory.createEntityManager();
  
  manager.getTransaction().begin();
  
  Endereco endereco = new Endereco();
  endereco.setRua("Rua 27");
  endereco.setCep("65364-972");
  endereco.setNumero(444);
  
  Aluno aluno = new Aluno();
  aluno.setNome("Maria Eduarda");
  aluno.setEndereco(endereco);
  
  Escola escola = new Escola();
  escola.setNome("São Francisco das Chagas");
  escola.getAlunos().add(aluno);
  
  manager.persist(escola);
  manager.getTransaction().commit();
  manager.close();
  factory.close();
  
 }
Criamos uma instancia de endereco e passamos os valores nos campos.
Observe que a partir de aluno conseguimos pegar todos os valores passado na classe endereco com aluno.setEnderco(endereco).
Fizemos o mesmo para escola, instanciamos a classe passamos os valores e adicionamos na coleção o objeto aluno para que o id do aluno seja referenciado na tabela.

Observe no banco de dados que foi criado uma terceira tabela chamada escola_aluno aonde é passado o id da escola e o id de aluno.

Veja tambem que nao foi preciso persistir o objeto aluno, o elemento cascade = CascadeType.PERSIST como foi explicado anteriormente ele persist todos os objetos que se referencia a classe escola e aluno.

Se tudo ocorrer bem no seu banco de dados vai ter os seguintes valores:

mysql> select * from aluno;
+----+-----------+--------+--------+---------------+
| id | cep | numero | rua | nome |
+----+-----------+--------+--------+---------------+
| 1 | 65364-972 | 444 | Rua 27 | Maria Eduarda |
+----+-----------+--------+--------+---------------+

mysql> select * from escola;
+----+---------------------------+
| id | nome |
+----+---------------------------+
| 1 | São Francisco das Chagas |
+----+---------------------------+

mysql> select * from escola_aluno;
+-----------+-----------+
| escola_id | alunos_id |
+-----------+-----------+
| 1 | 1 |
+-----------+-----------+


1.3 ManyToOne

No relacionamento ManyToOne (Muitos para UM), irei fazer como exemplo um relacionamento entre Filme e Categoria se "em caixa" perfeitamente nessa condição, aonde muitos Filme pode ter uma Categoria.

1.3.1 Vamos criar uma classe chamada Filme dentro do package br.com.vejajava.entidades

@Entity
@Table(name = "filme")
public class Filme {

 @Id
 @GeneratedValue
 private Long id;

 private String nome;

 @Temporal(TemporalType.DATE)
 @Column(name="data_cadastro")
 private Date dataCadastro;

 @ManyToOne
 private Categoria categoria;

           //getters e setters
}

Observe que temos uma anotação que ainda nao foi usada no projeto. @Temportal(TemporalType.DATE) no campo dataCadastro. A anotação TemporalType.DATE faz com que seja salvo no banco de dados a seguite data 2013-08-28.
Tambem temos anotação @ManyToOne que faz com que mais de um filme pode ter uma categoria.

Outros tipos de TemporalType:
TemporalType.DATE = data (dia, mês e ano).
TemporalType.TIME = Horário (hora, minuto e segundo)
TemporalType.TIMESTAMP (Padrão) = Data e Horário


1.3.2 Vamos criar uma classe chamada Categoria dentro do package br.com.vejajava.entidades

@Entity
@Table(name="categoria")
public class Categoria {
  
 @Id
 @GeneratedValue
 private Long id;
 
 private String descricao;

           //getters e setters
}
Na classe categoria temos apenas o campo id que se refere a primary key da tabela e a descricao que será o nome categoria.

1.3.3 Vamos criar uma classe chamada TesteManyToOne dentro do package br.com.vejajava.principal para fazer o teste do nosso relacionamento.

public class TesteManyToOne {
 public static void main(String[] args) {
  
  EntityManagerFactory factory = Persistence.createEntityManagerFactory("Mapeamento");
  EntityManager manager = factory.createEntityManager();
  
  manager.getTransaction().begin();
  
  Categoria categoria = new Categoria();
  categoria.setDescricao("Infantil");
  
  Filme filme = new Filme();
  filme.setNome("Pokémon");
  filme.setDataCadastro(new Date());
  filme.setCategoria(categoria);
  
  manager.persist(filme);
  manager.persist(categoria);

  manager.getTransaction().commit();
  
  manager.close();
  factory.close();
 }
}
Instanciamos a classe categoria e passamos o valor no campo descricao.
O mesmo foi feito na classe Filme o campo data ao ser salvo no banco registrará a data atual do máquina.
Veja também que passamos o valores da Categoria para o objeto filme.
Persistimos os dois objetos e depois fizemos o commit.

Se tudo ocorrer bem no seu banco de dados vai ter os seguintes valores:

mysql> select * from filme;
+----+---------------+----------+--------------+
| id | data_cadastro | nome | categoria_id |
+----+---------------+----------+--------------+
| 1 | 2013-08-28 | Pokémon | 1 |
+----+---------------+----------+--------------+

mysql> select * from categoria;
+----+-----------+
| id | descricao |
+----+-----------+
| 1 | Infantil |
+----+-----------+

o tópico 1.4 ManyToMany vou explicar criando o projeto exclusivo para esse mapeamento em outro post.

Obrigado pela visita.

Duvidas, Criticas e Sugestões ?

=D

2 comentários:

  1. Uma dúvida, no mapeamento oneToOne se eu colocar cascadeType.ALL não deveria funcionar tmb?

    ResponderExcluir
    Respostas
    1. Olá Diogo, desculpe a demora, pois nao chegou sua pergunta no meu email.

      Respondendo sua pergunta:
      Sim você conseguiria persistir os dados e nao precisaria persist as duas classes para conseguir os valores.

      Mas tem que ter muito cuidado com isso pois se voce persistir apenas a classe que nao manda no relacionamento voce nao consegue relacionar com a outra classe e a chave estrangeira nao seria alimentada.

      A solução seria persistir somente a classe que manda no relacionamento assim você teria uma relação uma com a outra e os dois seria persistido normalmente sem problemas.

      Obrigado





      Excluir