quinta-feira, 9 de agosto de 2012

Entendendo a persistência de dados e criação de tabelas pelo JPA


Este material foi desenvolvimento com o objeto de estudar o recurso de geração automática do banco oferecido pelo Java Persistence API pelo framework toplink. O estudo tratará das possibilidades uni e bidirecional das associações @ManyToOne e @OneToMany no modelo e seus respectivos reflexos na base de dados.

Como optar entre relações unidirecionais ou bidirecionais?
Em alguns modelos, talvez não seja necessário que o relacionamento entre dois objetos seja bidirecional. Isto ocorre quando um objeto não precisa conhecer o outro lado da associação. Um caso bem simples seria do relacionamento entre as entidades Militar e PostoGraduacao. Um objeto Militar possui um único PostoGraduacao (por exemplo, 3º Sargento ou 1º Tenente) e um objeto PostoGraduacao está associado com vários objetos Militar.


Observe que, na maioria das abstrações dos sistemas existentes, o objeto Militar precisa conhecer o objeto PostoGraduacao. Porém, um PostoGraduacao não precisa conhecer quais militares ele está associado. Suponha que você levantasse (instanciasse na memória) uma listagem (por exemplo, através da coleção List<PostoGraduacao>) do objeto PostoGraduacao para compor um ComboBox. Seria impraticável se cada um desses objetos PostoGraduacao possuíssem a listagem completa dos objetos Militar associados, ou seja, o objeto “3º Sargento” com sua listagem de militares associados – objetos “João”, “Pedro”, “Maria”, etc. Isso significa que neste relacionamento @ManyToOne (muitos para um, do ponto de vista do objeto Militar), somente o objeto Militar terá o atributo e a respectiva anotação para conhecer o relacionamento. O objeto PostoGraduacao não precisa (na verdade, não deve) conhecer quais militares estão associados a ele.
Existe também outro fator que deve ser considerado ao optar entre relacionamentos uni e bidirecionais: o acoplamento desnecessário entre os objetos e pacotes. Dois objetos talvez não precisem ter relacionamento bidirecional e neste caso, ao optar pelo relacionamento unidirecional, estaremos evitando um desacoplamento inviável e desnecessário. No caso de objetos dispostos em pacotes distintos, a situação torna-se mais crítica. Veja o exemplo fictício mostrado no diagrama abaixo:


O relacionamento entre dois pacotes não pode (não é recomendado) conter dependência mútua. Ou seja, se o relacionamento entre Militar e PostoGraduacao for bidirecional, significa que o objeto Militar depende de PostoGraduacao e que o objeto PostoGraduacao depende de Militar. Quando estes objetos estão em pacotes diferentes, significa que o pacote model.one depende do pacote model.two que o pacote model.two também depende do pacote model.one. Este tipo de situação é inviável do ponto de vista da orientação a objetos. Em casos como este, o relacionamento bidirecional deve ser evitado ou a distribuição dos objetos nos pacotes deve ser reestruturada.

Relacionamento @ManyToOne unidirecional
Vamos ao caso prático! O contexto abordado anteriormente serve como caso prático para esse tipo de relacionamento. O diagrama abaixo retrata a associação pertinente entre os objetos Militar e PostoGraduacao. Como já explicado, um Militar precisa conhecer seu PostoGraduacao, porém o inverso não é verdadeiro.


Isso mostra claramente que no caso do Militar, existe a necessidade da anotação @ManyToOne, ou seja, existem muitos militares para um único posto/graduação. A seguir temos os códigos necessários para o desenvolvimento deste estudo.
O arquivo persistence.xml segue abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<class>model.manytoone.PostoGraduacao</class>
<class>model.manytoone.Militar</class>
<properties>
<property name="toplink.jdbc.user" value="root" />
<property name="toplink.jdbc.password" value="root" />  
<property name="toplink.jdbc.url" 
value="jdbc:mysql://localhost:3306/ejb" /> 
<property name="toplink.jdbc.driver" 
value="com.mysql.jdbc.Driver"/>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>

Observe a configuração do arquivo. Com os parâmetros toplink.jdbc.user e toplink.jdbc.password são definidos, respectivamente, os valores do usuário e senha de acesso ao banco. O parâmetro toplink.jdbc.url define o valor da string de conexão, o valor de toplink.jdbc.driver define o driver utilizado para acessar o banco (no caso, para o banco MySQL) e o parâmetro toplink.dll-generation define o algoritmo de geração automática do banco. Neste caso, as tabelas são criadas automaticamente. Através das propriedades class, os objetos persistidos são definidos.
Abaixo, o arquivo do objeto PostoGraduacao.java:

package model.manytoone;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;

@Entity( name = "PostoGraduacao" )
@Table( name = "postosgraduacoes" )
public class PostoGraduacao implements Serializable {

   private static final long serialVersionUID = 1379657866927537568L;
   @Id
   @GeneratedValue
   @Column( name = "id" )
   private Long id;
   @Column( name = "descricao" , nullable = false )
   private String descricao;
   public Long getId() {
     return id;
   }
   public void setId(Long id) {
     this.id = id;
   }
   public String getDescricao() {
     return descricao;
   }
   public void setDescricao(String descricao) {
     this.descricao = descricao;
   }
}

A definição das anotações pode ser entendida pelo conteúdo abaixo:
@Entity – define o nome da entidade
@Table – define o nome da tabela do banco de dados associada com essa entidade
@Id – define que o atributo é a chave primária na tabela
@GeneratedValue – define que o valor do atributo será gerado automaticamente pelo banco
@Column – define as propriedades do atributo no banco de dados

Observe que neste caso, conforme planejado, não existe nenhuma ligação com o objeto Militar. Vamos agora analisar o código fonte Militar.java:

package model.manytoone;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;

@Entity( name = "Militar" )
@Table( name = "militares" )
public class Militar implements Serializable {
   private static final long serialVersionUID = 2485833714032900145L;
   @Id
   @GeneratedValue
   @Column( name = "id" )
   private Long id;
   @Column( name = "nome" )
   private String nome;
   /** 
   * Nesta tabela haverá um campo chamado postograduacao_id foreign key
    * do campo id na tabela postosgraduacoes.
   */
   @ManyToOne( optional = false )
   @JoinColumn( name = "postograduacao_id" , referencedColumnName = "id" )
   private PostoGraduacao postoGraduacao;
   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 PostoGraduacao getPostoGraduacao() {
     return postoGraduacao;
   }
   public void setPostoGraduacao(PostoGraduacao postoGraduacao) {
     this.postoGraduacao = postoGraduacao;
   }

}

Veja que neste caso, além das anotações comuns, existe a anotação @ManyToOne qualificando o atributo PostoGraduacao como relacionamento entre as tabelas no banco de dados. Pela anotação @JoinColumn são especificados: (1) o nome do campo de chave estrangeira que será criado na tabela militares responsável por armazenar a chave primária da tabela postosgraduacoes (parâmetro name); (2) o nome da própria chave primária da tabela postosgraduacoes (parâmetro referencedColumnName).
Esses objetos poderão ser inseridos no banco através de uma unidade de persistência. Abaixo temos o código do arquivo AbstractDAO.java:

package dao;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import javax.persistence.PersistenceUnit;

@PersistenceUnit
public class AbstractDAO {

   private static EntityManagerFactory emf = Persistence
.createEntityManagerFactory("default");
   private static EntityManager em = emf.createEntityManager();
   private static AbstractDAO dao;

   public AbstractDAO() { }

   public static AbstractDAO getInstance() {
     if (dao == null) dao = new AbstractDAO();
     return dao;
   }

   public void create(Object object) throws PersistenceException {
     try {
       em.getTransaction().begin();
       em.persist(object);
       em.getTransaction().commit();
       em.clear();
     } catch (Exception e) {
       throw new PersistenceException("Não foi possível criar o objeto!");
     }
   }
}

Observe que este objeto foi criado com base no pattern Singleton e que só possui um método de cadastrado – chamado de create. Com esta unidade de persistência, podemos concluir nosso exemplo com um código de teste, chamado de TestDriver.java:
 
package engine;

import model.manytoone.*;
import dao.AbstractDAO;

public class TestDriver {
   public static void main(String args[]) {
     PostoGraduacao grad = new PostoGraduacao();
     grad.setDescricao( "2º Tenente" );
     Militar mil1 = new Militar();
     mil1.setNome( "Guilherme" );
     mil1.setPostoGraduacao( grad );
     Militar mil2 = new Militar();
     mil2.setNome( "João" );
     mil2.setPostoGraduacao( grad );
     AbstractDAO.getInstance().create( grad );
     AbstractDAO.getInstance().create( mil1 );
     AbstractDAO.getInstance().create( mil2 );
   }

}

Este é um simples exemplo para testar o funcionamento do estudo. Após executar esse teste, teremos os resultados apresentados abaixo no MySQL. Atenção: deve ser criado um banco de nome ejb no banco de dados. Atente-se também que o usuário root possui a senha root.


Conforme previsto, a tabela militares possui um campo postograduacao_id que referencia o campo id da tabela postosgraduacoes. A tabela sequence é responsável pela geração dos id automaticamente. Os dados inseridos podem ser visualizados abaixo:


Este foi um caso de relacionamento unidirecional para @ManyToOne. Os demais exemplos não trarão os códigos dos arquivos persistence.xml e AbstractDAO.java, pois estes podem ser facilmente adaptados de acordo com o estudo. Especificamente, o arquivo AbstractDAO.java não precisará ser modificado. Atente-se na inserção de novas chaves <class></class> no arquivo persistence.xml para que o mesmo comporte as classes criadas nos próximos exemplos.

Relacionamento @ManyToOne bidirecional
Vamos ver agora um caso em que o relacionamento @ManyToOne precisa ser bidirecional – ou seja, neste caso, os objetos precisam tomar conhecimento da existência do relacionamento com o outro objeto.


Neste caso, o objeto Militar possui vários documentos e o objeto Documento pertence a um único Militar. Isso ocorre por que na prática, uma pessoa precisa saber quais são os seus documentos e um documento possui a identificação da pessoa (sabe de quem ele é). A anotação @ManyToOne deve ficar no objeto Documento e, como o objeto Militar também precisa conhecer seus documentos, terá uma anotação @OneToMany. Abaixo temos o código do arquivo Militar.java – observe que este foi modificado, porém ainda mantém sua associação com o objeto PostoGraduacao.

package model.manytoone;

import java.io.Serializable;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.JoinColumn;

@Entity( name = "Militar" )
@Table( name = "militares" )
public class Militar implements Serializable {
   private static final long serialVersionUID = 2485833714032900145L;
   @Id
   @GeneratedValue
   @Column( name = "id" )
   private Long id;
   @Column( name = "nome" )
   private String nome;
   @ManyToOne( optional = false )
   @JoinColumn( name = "postograduacao_id" , referencedColumnName = "id" )
   private PostoGraduacao postoGraduacao;
   @OneToMany( mappedBy = "meuDono" )
   private List<Documento> documentos;
   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 PostoGraduacao getPostoGraduacao() {
     return postoGraduacao;
   }
   public void setPostoGraduacao(PostoGraduacao postoGraduacao) {
     this.postoGraduacao = postoGraduacao;
   }
   public void setDocumentos(List<Documento> documentos) {
     this.documentos = documentos;
   }
   public List<Documento> getDocumentos() {
     return documentos;
   }

}

A única alteração em Militar corresponde ao atributo documentos que é uma coleção List<Documento> qualificada pela anotação @OneToMany. Observe a existência do parâmetro mappedBy que indica o nome do atributo no objeto Documento que está associado a este relacionamento – no caso meuDono, que representa justamente o objeto “dono” do documento. O fato de se trabalhar com uma coleção indica que este objeto possui muitos documentos, exatamente como mostrado no modelo. À critério de entendimento, a anotação @OneToMany indica que existe um objeto Militar para muitos objetos Documento.
Veremos agora o arquivo Documento.java:

package model.manytoone;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;

@Entity( name = "Documento" )
@Table( name = "documentos" )
public class Documento implements Serializable {

   private static final long serialVersionUID = 7563299527052904816L;

   @Id
   @GeneratedValue
   @Column( name = "id" )
   private Long id;

   @Column( name = "descricao" , length = 50, nullable = false )
   private String descricao;
   @ManyToOne( optional = false )
   @JoinColumn( name = "militar_id" , referencedColumnName = "id" )
   private Militar meuDono;
   public Long getId() {
     return id;
   }
   public void setId(Long id) {
     this.id = id;
   }
   public String getDescricao() {
     return descricao;
   }
   public void setDescricao(String descricao) {
     this.descricao = descricao;
   }
   public void setMeuDono(Militar meuDono) {
     this.meuDono = meuDono;
   }
   public Militar getMeuDono() {
     return meuDono;
   }

}

Conforme definido, este objeto possui um atributo meuDono que representa uma referência para um tipo Militar. Este atributo foi definido com a anotação @ManyToOne, de funcionamento similar ao exemplo tratado neste estudo. Vamos ao código de teste TestDriver.java:

package engine;

import model.manytoone.*;
import dao.AbstractDAO;

public class TestDriver {
   public static void main(String args[]) {
     PostoGraduacao grad = new PostoGraduacao();
     grad.setDescricao( "2º Tenente" );
     Militar mil1 = new Militar();
     mil1.setNome( "Guilherme" );
     mil1.setPostoGraduacao( grad );
     Documento doc1 = new Documento();
     doc1.setDescricao( "CPF" );
     doc1.setMeuDono( mil1 );
     Documento doc2 = new Documento();
     doc2.setDescricao( "Identidade" );
     doc2.setMeuDono( mil1 );
     Militar mil2 = new Militar();
     mil2.setNome( "João" );
     mil2.setPostoGraduacao( grad );
     AbstractDAO.getInstance().create( grad );
     AbstractDAO.getInstance().create( mil1 );
     AbstractDAO.getInstance().create( mil2 );
     AbstractDAO.getInstance().create( doc1 );
     AbstractDAO.getInstance().create( doc2 );
   }

}

Após executarmos esse programa, o resultado encontrado no MySQL será:


Conforme esperado, a tabela documentos possui um campo militar_id utilizado como chave estrangeira para o campo id (chave primária) da tabela militar.

Relacionamento @OneToMany unidirecional
Vamos agora ao entendimento do relacionamento @OneToMany unidirecional. Este é um caso típico onde um objeto qualquer possua uma coleção de outros objetos, sendo que, o objeto um da relação conhece sua coleção, porém nenhum dos objetos muitos precisa saber a qual objetos estão relacionados. Veja um exemplo abaixo:


Neste caso, o objeto Militar possui uma coleção de telefones e precisa conhecer cada um deles. Já o objeto Telefone não conhece com qual objeto está relacionado. Neste caso, vamos utilizar apenas a anotação @OneToMany no lado do objeto Militar.
Veja abaixo o código de Telefone.java:

package model.manytoone;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;

@Entity( name = "Telefone" )
@Table( name = "telefones" )
public class Telefone implements Serializable {

   private static final long serialVersionUID = 7451235917815653206L;
   @Id
   @GeneratedValue
   @Column( name = "id" )
   private Long id;
   @Column( name = "numero" , nullable = false )
   private String numero;
   public Long getId() {
     return id;
   }
   public void setId(Long id) {
     this.id = id;
   }
   public String getNumero() {
     return numero;
   }
   public void setNumero(String numero) {
     this.numero = numero;
   }
}

Este arquivo é simples. Veremos agora o arquivo Militar.java que mais uma vez foi modificado.

package model.manytoone;

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

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.JoinColumn;

@Entity( name = "Militar" )
@Table( name = "militares" )
public class Militar implements Serializable {
   private static final long serialVersionUID = 2485833714032900145L;
   @Id
   @GeneratedValue
   @Column( name = "id" )
   private Long id;
   @Column( name = "nome" )
   private String nome;
   @ManyToOne( optional = false )
   @JoinColumn( name = "postograduacao_id" , referencedColumnName = "id" )
   private PostoGraduacao postoGraduacao;
   @OneToMany( mappedBy = "meuDono" )
   private List<Documento> documentos;
   @OneToMany
   private List<Telefone> telefones;
   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 PostoGraduacao getPostoGraduacao() {
     return postoGraduacao;
   }
   public void setPostoGraduacao(PostoGraduacao postoGraduacao) {
     this.postoGraduacao = postoGraduacao;
   }
   public void setDocumentos(List<Documento> documentos) {
     this.documentos = documentos;
   }
   public List<Documento> getDocumentos() {
     return documentos;
   }
   public void setTelefones(List<Telefone> telefones) {
     this.telefones = telefones;
   }
   public List<Telefone> getTelefones() {
     return telefones;
   }

}

Observe que neste caso, a anotação @OneToMany do atributo telefones não possui nenhum parâmetro informativo. Abaixo, temos o arquivo de teste TestDriver.java:

package engine;

import java.util.ArrayList;
import java.util.List;

import model.manytoone.Documento;
import model.manytoone.Militar;
import model.manytoone.PostoGraduacao;
import model.manytoone.Telefone;
import dao.AbstractDAO;

public class TestDriver {
   public static void main(String args[]) {
     PostoGraduacao grad = new PostoGraduacao();
     grad.setDescricao( "2º Tenente" );
     Militar mil1 = new Militar();
     mil1.setNome( "Guilherme" );
     mil1.setPostoGraduacao( grad );
     Telefone tel1 = new Telefone();
     tel1.setNumero( "(11) 1111-1111" );
     Telefone tel2 = new Telefone();
     tel2.setNumero( "(22) 2222-2222" );
     List<Telefone> telefones = new ArrayList<Telefone>();
     telefones.add( tel1 );
     telefones.add( tel2 );
     mil1.setTelefones( telefones );
     Documento doc1 = new Documento();
     doc1.setDescricao( "CPF" );
     doc1.setMeuDono( mil1 );
     Documento doc2 = new Documento();
     doc2.setDescricao( "Identidade" );
     doc2.setMeuDono( mil1 );
     Militar mil2 = new Militar();
     mil2.setNome( "João" );
     mil2.setPostoGraduacao( grad );
     AbstractDAO.getInstance().create( tel1 );
     AbstractDAO.getInstance().create( tel2 );
     AbstractDAO.getInstance().create( grad );
     AbstractDAO.getInstance().create( mil1 );
     AbstractDAO.getInstance().create( mil2 );
     AbstractDAO.getInstance().create( doc1 );
     AbstractDAO.getInstance().create( doc2 );
   }

}

Após executarmos este arquivo, o seguinte resultado será encontrado:


Este é um caso interessante. Veja que o JPA gerou, além das tabelas associadas às entidades Telefone e Militar, uma outra tabela chamada militares_telefones. Isso ocorre pelo fato de que, na prática, para armazenar vários telefones na tabela militares, teriam que existir dados duplicados (militar de código 1 com telefone de código 1, militar de código 1 com telefone de código 2). Isso faria com que o banco ficasse desnormalizado (fora das formas normais). Por isso o próprio framework criou uma tabela associativa para relacionar essas tabelas. Podemos especificar os dados dessa tabela explicitamente com a anotação @JoinTable.

   @OneToMany
   @JoinTable(
   name = "agenda_telefones" ,
   joinColumns=@JoinColumn( name = "militar_id" ) ,
   inverseJoinColumns=@JoinColumn( name = "telefone_id" ))
   private List<Telefone> telefones;

Desta forma, a tabela de associação entre os elementos seria chamada de agenda_telefones, o campo relacionado à tabela militares seria militar_id e o campo relacionado à tabela telefones seria telefone_id.


Relacionamento @OneToMany bidirecional
Este caso é similar ao caso do relacionamento @ManyToOne bidirecional, só que deve ser entendido do lado um. Seria o caso de colocar o problema sob outra perspectiva. Por exemplo, o objeto Militar possui muitos objetos Documento, sendo que cada um desses documentos conheçam o outro lado do relacionamento (no caso, o Militar). O código para geração deste estudo é exatamente igual ao código mostrado no caso @ManyToOne de Militar/Documento.

Conclusões
Deve-se sempre priorizar a necessidade do modelo na escolha do tipo de relacionamento, lembrando também do tipo de relacionamento que será criado no banco. Ao optar em manter uma forte confiabilidade e integridade no banco de dados, talvez sejam necessárias alterações nos relacionamentos do modelo. Por exemplo, um relacionamento @OneToMany unidirecional entre dois objetos no qual o lado muitos não pode conhecer os elementos do lado um implicariam na criação de uma terceira tabela apenas para manter os relacionamentos no banco (como no exemplo mostrado em @OneToMany unidirecional). Porém, essa tabela, de fato, poderia ser suprimida com um relacionamento simples de chave estrangeira.
Este estudo concentrou-se na implementação do modelo abaixo:


Revisando o entendimento dos relacionamentos, temos os seguintes detalhes:

  1. O objeto Militar possui um relacionamento com PostoGraduacao, sendo que, Militar precisa conhecer o relacionamento e PostoGraduacao não. Por isso Militar possui um atributo PostoGraduacao qualificado pela anotação @ManyToOne
  2. Militar possui uma coleção de objetos Documento e cada objeto Documento está associado com um único Militar. Deve ser considerado que neste caso, ambos objetos precisam conhecer o outro lado do relacionamento. Por conseqüência, Militar possui um atributo List<Documento> definido com uma anotação @OneToMany e Documento possui um atributo Militar definido com @ManyToOne. Neste caso temos o relacionamento bidirecional.
  3. Por fim, o objeto Militar possui uma coleção de objetos Telefone e cada Telefone pertence a um único Militar. Neste caso, Telefone não precisa conhecer a qual objeto Militar ele pertence, porém o objeto Militar precisa conhecer todos seus objetos Telefone. Desta forma, Militar possui um atributo List<Telefone> qualificado com as anotações @OneToMany e @JoinTable, respectivamente, usadas para definir o tipo de associação e para identificar a tabela associativa entre as tabelas geradas.
Observado os detalhes da modelagem, através da geração automática, conquistou-se o seguinte modelo E/R (Modelo de Entidade e Relacionamento):

 
Cabe a equipe de projeto analisar cada situação de forma particular, considerando que as formatações escolhidas para as anotações JPA terão diferentes conseqüências no padrão de geração das tabelas no banco de dados.
 
Download do Projeto (código fonte)
Você poderá realizar o download deste projeto, desenvolvido no Eclipse, através do link abaixo.

Referências
http://rfiume.blogspot.com/2007/04/relacionamento-one-to-many-e-many-to.html
http://www.slideshare.net/cmilfont/course-hibernate-2008-presentation

Porquê aderir a Marinha se você pode ser um pirata? - Steven Jobs
Espero ter ajudado!
Guilherme Pontes

Nenhum comentário:

Postar um comentário