Mapeando Associações com Hibernate - Parte 1por: Raphaela Galhardo (raphaela@jeebrasil.com.br) Este tutorial apresenta os mapeamentos no Hibernate de relacionamentos entre entidades. Os mapeamentos apresentados são: 1-para-n, n-para-1 e n-para-n. O próximo tutorial consiste na segunda parte do tutorial sobre Associações, onde serão mapeadas associações n-para-n com atributos e 1-para-1. AssociaçõesO termo associação é utilizado para se referir aos relacionamentos entre as entidades. Os relacionamentos n-para-n, n-para-1 e 1-para-n são os mais comuns entre as entidades de um banco de dados. Todos os exemplos apresentados nesta seção baseiam-se no diagrama de classes mostrado na Figura 1 do Tutorial "Primeiro Exemplo com Hibernate". Associações 1-n (one-to-many)Para exemplificar o relacionamento 1-n, considere o relacionamento entre a entidade Centro e a entidade Universidade da Figura 1. O relacionamento diz que uma universidade possui um conjunto de n centros e um centro está associado a apenas uma única universidade. Considere as classes de domínio Java de uma universidade e de um centro, respectivamente, mostradas nas Listagens 1 e 2.
Figura 1 - Relacionamento entre Centro e Universidade package br.com.jeebrasil.dominio; import java.util.Collection; public class Universidade implements Serializable{ private int id; private String nome; private Endereco endereco; private Collection centros; //Implementação dos métodos setter e getter ... } Listagem 1 - Classe de Domínio: Universidade package br.com.jeebrasil.dominio; import java.util.Collection; public class Centro implements Serializable{ private int id; private String nome; private Universidade universidade; //departamentos -> Atributo mapeado das mesma forma que a //coleção centros em Universidade private Collection departamentos; //Implementação dos métodos setter e getter } Listagem 2 - Classe de Domínio: Centro A classe de domínio Universidade é a que possui um mapeamento do tipo 1-n. O seu mapeamento pode ser visto na Listagem 3. Neste momento, as informações do endereço da universidade foram desconsideradas. ... <hibernate-mapping> <class name="br.com.jeebrasil.dominio.Universidade" table="UNIVERSIDADE"> <id name="id" column="ID_UNVERSIDADE" type="int"> <generator class="increment"/> </id> <property name="nome"/> <!-- Mapeamento da Coleção de centros --> <set name="centros" inverse="true" lazy="true"> <key column="ID_UNIVERSIDADE"/> <one-to-many class="br.com.jeebrasil.dominio.Centro"/> </set> </class> </hibernate-mapping> Listagem 3 - Mapeamento 1-n: tabela universidade Observa-se que para realizar o mapeamento 1-n, ou seja, da coleção centros foi utilizada uma tag set. Um set ou um conjunto representa uma coleção de objetos não repetidos que podem ou não estar ordenados. O atributo name define a propriedade que está sendo tratada para realizar o relacionamento 1-n. O atributo key representa a coluna da tabela relacionada (Centro) que possui a chave estrangeira para a classe Universidade. O nome da coluna da chave estrangeira (ID_UNIVERSIDADE) é informado no atributo column. Na tag <one-to-many> informa-se a classe a qual pertence à coleção de objetos, no caso br.com.jeebrasil.dominio.Centro. A tag set também apresenta um atributo denominado inverse. Esse atributo é utilizado para que o Hibernate saiba como tratar a associação entre duas tabelas. Quando um lado da associação define o atributo inverse como true, indica que a ligação do relacionamento entre a associação será de responsabilidade do "outro lado" da associação. Considerando o relacionamento entre uma universidade e seus centros, no mapeamento do conjunto de centros em universidade, o atributo inverse é igual a true. Dessa forma, a criação ou atualização do relacionamento entre um centro e uma universidade será feita durante a persistência ou atualização de um objeto Centro. A partir do exemplo apresentado na Listagem 4, cria-se uma instância da classe Universidade e define-se um valor para o atributo nome. Em seguida, uma instância da classe Centro também é criada, definindo o atributo nome e o atributo universidade (como sendo a instância de Universidade anteriormente criada). Por fim, o objeto Centro criado é adicionado à coleção de centros do objeto Universidade, o qual é persistido. ... Universidade univ = new Universidade() univ.setNome("Universidade Federal do Rio Grande do Norte"); Centro centro = new Centro(); centro.setNome("Centro de Tecnologia"); centro.setUniversidade(univ); univ.setCentros(new HashSet Listagem 4 - Exemplificando uso do atributo inverse A Listagem 5 apresenta o que acontece se o atributo inverse no mapeamento 1-n for definido como false. O que acontece é que o Hibernate insere uma linha na tabela UNIVERSIDADE e em seguida tenta atualizar o relacionamento entre uma universidade e um centro, no caso a partir de um UPDATE na tabela CENTRO, setando a chave estrangeira para a tabela UNIVERSIDADE. Hibernate: insert into UNIVERSIDADE (nome, ID_ENDERECO, ID_UNIVERSIDADE) values (?, ?, ?) Hibernate: update CENTRO set ID_UNIVERSIDADE=? where ID_CENTRO=? Listagem 5 – SQL gerado pelo Hibernate com atributo inverse=false Verifica-se, então, que com o atributo inverse sendo igual a false, o Hibernate tenta atualizar o relacionamento entre uma universidade e um centro logo após a inserção da universidade. Neste caso, como o relacionamento com a universidade está sendo feito com um objeto transiente de um Centro, o que vai ocorrer é que o Hibernate vai tentar atualizar a chave estrangeira para a tabela UNIVERSIDADE em uma linha da tabela CENTRO que não existe, acontecendo o erro exibido na Listagem 6. ERRO: Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.jeebrasil.dominio.Centro ... Listagem 6 – Erro gerado após teste com o atributo inverse=false no relacionamento 1-n em Universidade De acordo com o mapeamento da Listagem 3, o atributo inverse é definido como true. Então, para o código da Listagem 4 vai ser gerado o SQL exibido na Listagem 7. Neste caso, veja que apenas é dado um INSERT na tabela UNIVERSIDADE, ou seja, no momento da inserção de uma universidade o Hibernate não atualiza o relacionamento entre ela e seus centros, pois espera que ele seja feito no momento da inserção/atualização de um objeto Centro. Hibernate: insert into UNIVERSIDADE (nome, ID_ENDERECO, ID_UNIVERSIDADE) values (?, ?, ?) Listagem 7 - SQL gerado pelo Hibernate com atributo inverse=true Resumindo, se o atributo inverse não for definido como true, o Hibernate não tem como saber qual dos dois lados foi atualizado, ou seja, vai sempre atualizar os dois lados de uma vez, uma atualização para cada classe da relação, o que seria desnecessário. Caso contrário, o Hibernate passa a saber de qual lado fazer a atualização e fazendo uma única vez. Na tag set também está presente o atributo lazy. Ele é utilizado para resolver o seguinte problema: quando se realiza um select em um objeto Universidade implica em serem feitos n (número de centros da universidade) outros select’s para buscar os seus centros. Dessa forma, a resolução do problema é feita apenas definindo o atributo lazy como sendo true. A coleção de centros passa a ser lazy-loading, o que significa que somente será recuperada quando solicitada, ou seja, a coleção de centros de uma universidade só seria solicitada caso o programador a acesse através da chamada ao método getCentros(). Associações n-1 (many-to-one)O relacionamento n-1 será apresentado a partir do relacionamento <many-to-one> existente entre a tabela Centro e a tabela Universidade. Neste caso, o relacionamento está presente no mapeamento da classe Centro, como mostrado na Listagem 8. ... <hibernate-mapping> <class name="br.com.jeebrasil.dominio.Centro" table="CENTRO"> <id name="id" column="ID_CENTRO" type="int"> <generator class="increment"/> </id> <property name="nome" type="java.lang.String"/> <!-- Mapeamento da Universidade --> <many-to-one name="universidade" class="br.jeebrasil.dominio.Universidade" cascade="none" fech="join" update="true" insert="true" lazy="true" column="id_universidade"/> <set name="departamentos" lazy="true" inverse="true"> <key column="ID_CENTRO"/> <one-to-many class="br.com.jeebrasil.dominio.Departamento"/> </set> </class> </hibernate-mapping> Listagem 8 - Mapeamento n-1: tabela centro Como mostrado no mapeamento da classe Centro, o relacionamento n-1 é mapeado a partir da tag <many-to-one>. Essa tag apresenta um conjunto de atributos, que podem assumir os valores apresentados na Listagem 9. <many-to-one name="propertyName" class="ClassName" column="column_name" fetch="join|select" update="true|false" lazy="true|false" insert="true|false" cascade="all|none|save-update|delete" /> Listagem 9 – Mapeamento n-1: atributos
Associações n-n (many-to-many)O relacionamento n-n será feito a partir do relacionamento entre as entidades Departamento e Curso mostrado na Figura 2.
Figura 2 - Relacionamento n-n entre Curso e Departamento Um relacionamento n-n implica em existir uma nova tabela para mapear o relacionamento no banco de dados. Vamos denominar essa nova tabela como DEPARTAMENTO_CURSO, como mostrado na Figura 3. Dessa forma, um departamento possui uma coleção de cursos e um curso uma coleção de departamentos. A existência dessas coleções é opcional. Por exemplo, pode ser que em um sistema real não seja necessário saber todos os departamentos de determinado curso, mas se for realmente necessário, o Hibernate apresenta outros mecanismos para a obtenção desta informação.
Figura 3 - Tabela de relacionamento DEPARTAMENTO_CURSO As classes Java das entidades Departamento e Curso estão ilustradas nas Listagens 10 e 11, respectivamente. package br.com.jeebrasil.dominio; import java.util.Collection; public class Departamento implements Serializable{ private int id; private String nome; private String sigla; private Centro centro; private Collection professores; private Collection cursos; // Implementação dos métodos setter e getter } Listagem 10 - Classe de Domínio: Departamento package br.com.jeebrasil.dominio; import java.util.Collection; public class Curso implements Serializable{ private int id; private int codigo; private String nome; private String sigla; private Collection departamentos; private Collection alunos; //Implementação dos métodos setter e getter } Listagem 11 - Classe de Domínio: Curso A Listagem 12 apresenta o mapeamento da classe Departamento. Já a Listagem 13, o mapeamento da classe Curso. ... <hibernate-mapping> <class name="br.com.jeebrasil.dominio.Departamento" table="DEPARTAMENTO"> <id name="id" column="ID_DEPARTAMENTO" type="int"> <generator class="increment"/> </id> <property name="nome" type="java.lang.String"/> <property name="sigla" type="java.lang.String <many-to-one name="centro" class="br.com.jeebrasil.dominio.Centro" column="ID_CENTRO" cascade="save-update"/> <set name="professores"> <key column="ID_DEPARTAMENTO"/> <one-to-many class="br.com.jeebrasil.dominio.Professor"/> </set> <!-- Mapeamento dos cursos --> <set name="cursos" table="DEPARTAMENTO_CURSO" inverse="true"> <key column="ID_DEPARTAMENTO"/> <many-to-many column="ID_CURSO" class="br.com.jeebrasil.dominio.Curso"/> </set> </class> </hibernate-mapping> Listagem 12 - Departamento.hbm.xml ... <hibernate-mapping> <class name="br.com.jeebrasil.dominio.Curso" table="CURSO"> <id name="id" column="ID_CURSO" type="int"> <generator class="increment"/> </id> <property name="codigo"/> <property name="nome"/> <property name="sigla"/> <set name="alunos"> <key column="ID_CURSO"/> <one-to-many class="br.com.jeebrasil.dominio.Aluno"/> </set> <!-- Mapeamento dos departamentos--> <set name="departamentos" table="DEPARTAMENTO_CURSO"> <key column="ID_CURSO"/> <many-to-many column="ID_DEPARTAMENTO" class="br.com.jeebrasil.dominio.Departamento"/> </set> </class> </hibernate-mapping> Listagem 13 - Curso.hbm.xml Observa-se que tanto no mapeamento da coleção cursos em Departamento quanto no da coleção departamentos em Curso, o relacionamento n-n é feito a partir de uma tag set. Os mapeamentos das duas coleções apresentam uma tag key, na qual o atributo column indica a chave estrangeira do pai na tabela de relacionamento DEPARTAMENTO_CURSO. Apresentam também a tag many-to-many utilizada para indicar a entidade filha e sua chave estrangeira no relacionamento. A única diferença entre o mapeamento das duas coleções é que na tag set de cursos no mapeamento da entidade Departamento o atributo inverse é igual a true, significando que na tabela DEPARTAMENTO_CURSO só será inserido o relacionamento entre as duas entidades, quando um curso for inserido no banco de dados associado a um departamento. Neste caso, não seria necessário mapear a coleção de cursos em Departamento, pois não está sendo utilizada para popular a tabela de relacionamento. Como já citado, para recuperar a coleção de cursos de um departamento, o Hibernate apresenta outros mecanismos. Em outros relacionamentos n-n, pode ser que seja necessário inserir/atualizar o relacionamento na tabela de relacionamento durante a inserção/atualização de qualquer um dos lados das entidades, portanto, basta que o atributo inverse nas duas coleções seja mapeado como false. O código presente na Listagem 14 cria um instância de um objeto Departamento. Em seguida recupera um objeto persistente da classe Curso com identificador igual a 1, adiciona esse objeto Curso na coleção de cursos do objeto Departamento criado e, por fim, persiste o departamento. O SQL gerado é apresentado na Listagem 15. Observa-se que apenas um SELECT na tabela CURSO é feito e um INSERT na tabela DEPARTAMENTO. Não há uma inclusão de linha na tabela de relacionamento DEPARTAMENTO_CURSO, pois o atributo inverse da coleção de cursos no mapeamento da classe Departamento foi definido como true. Departamento depart = new Departamento(); depart.setNome("Departamento 1"); Curso curso = (Curso)session.get(Curso.class, 1); depart.getCursos().add(curso); session.save(depart); Listagem 14 - Persistência de Departamento Hibernate: select curso0_.ID_CURSO as ID1_0_, curso0_.codigo as codigo1_0_, curso0_.nome as nome1_0_, curso0_.sigla as sigla1_0_, curso0_.ID_COORDENADOR as ID5_1_0_ from CURSO curso0_ where curso0_.ID_CURSO=? Hibernate: insert into DEPARTAMENTO (nome, sigla, ID_CENTRO, ID_CHEFE, ID_DEPARTAMENTO) values (?, ?, ?, ?, ?) Listagem 15 - SQL para comandos da Tabela 14 Já o código presente na Listagem 16, cria uma instância da classe Curso, busca o objeto persistente Departamento de identificador 1 na base de dados, adiciona o departamento a coleção de departamentos do objeto Curso e realiza a a sua persistência. O SQL presente na Listagem 17 mostra que um SELECT foi feito na tabela DEPARTAMENTO, um INSERT na tabela CURSO e um outro INSERT na tabela DEPARTAMENTO_CURSO. Nesse caso, o relacionamento foi persistido, pois no mapeamento da coleção departamentos da classe Curso, como o atributo inverse não foi definido como true, assume-se que ele é false. Curso curso = new Curso(); Departamento d = (Departamento)session.get(Departamento.class, 1); curso.getDepartamentos().add(d); session.save(curso); Listagem 16 - Persistência de Curso Hibernate: select departamen0_.ID_DEPARTAMENTO as ID1_0_, departamen0_.nome as nome4_0_, departamen0_.sigla as sigla4_0_, departamen0_.ID_CENTRO as ID4_4_0_, departamen0_.ID_CHEFE as ID5_4_0_ from DEPARTAMENTO departamen0_ where departamen0_.ID_DEPARTAMENTO=? Hibernate: insert into CURSO (codigo, nome, sigla, ID_COORDENADOR, ID_CURSO) values (?, ?, ?, ?, ?) Hibernate: insert into DEPARTAMENTO_CURSO (ID_CURSO, ID_DEPARTAMENTO) values (?, ?) Listagem 17 - SQL para comandos da Tabela 16 ConclusõesO mapeamento de relacionamentos entre entidades será freqüente ao se utilizar um framework de mapeamento objeto-relacional. De início, mapeá-los utilizando Hibernate pode parecer uma tarefa difícil e tediosa, porém nada melhor do que a prática para ver que esse poderoso framework ajudará bastante o desenvolvedor e possibilitará redução no tempo de desenvolvimento de uma aplicação. Pratique! No próximo tutorial será apresentado o mapeamento do relacionamento 1-para-1 e do relacionamento n-para-n com atributos, onde também será apresentado o mapeamento de chaves compostas. Associações n-n com Atributos - Parte 2Imagine que seria necessário guardar a data em que foi feita a associação entre um determinado curso e um determinado departamento, ou seja, necessário ter um novo atributo na tabela DEPARTAMENTO_CURSO. Dessa forma, a tabela DEPARTAMENTO_CURSO não seria formada apenas pelos identificadores de curso e de departamento, mas sim também pela data. Para essa situação, os mapeamentos dos relacionamentos <many-to-many> nas tabelas Curso e Departamento não resolveriam o problema. Então, deve-se criar uma nova classe DepartamentoCurso, como mostrado no diagrama da Figura 1. Como pode ser visto nesta figura, existem agora relacionamentos <many-to-one> e uma chave primária dupla.
Figura 1 - Mapeamento n-n com Atributo Dessa forma, o mapeamento da tabela DEPARTAMENTO_CURSO seria feito como mostrado na Listagem 1. ... <hibernate-mapping> <class name="br.com.j2eebrasil.dominio.DepartamentoCurso" table="DEPARTAMENTO_CURSO"> <composite-id name="compositeID" class="br.com.j2eebrasil.dominio.DepartamentoCursoID"> <key-many-to-one name="curso" column="ID_CURSO" class="br.com.j2eebrasil.dominio.Curso"/> <key-many-to-one name="departamento " column="ID_DEPARTAMENTO" class="br.com.j2eebrasil.dominio.Departamento "/> </composite-id> <property name="data" type="java.util.Date" column="data"/> </class> </hibernate-mapping> Listagem 1 - DepartamentoCurso.hbm.xml Composite-idComo pode ser visto na Listagem 1, há o mapeamento de uma chave composta. Neste caso, a chave é um objeto da classe Curso e um objeto da classe Departamento. O primeiro passo é a criação de uma classe de domínio para a chave composta, DepartamentoCursoID (Listagem 2).public class DepartamentoCursoID implements Serializable{ private Departamento1 departamento; private Curso1 curso; //Métodos getter e setter ... } Listagem 2 - Classe de Domínio: DepartamentoCursoID Para esse exemplo, a classe DepartamentoCurso possuirá um atributo Date data e um atributo DepartamentoCursoID compositeID. Veja Listagem 3. public class DepartamentoCurso implements Serializable{ private DepartamentoCursoID compositeID; private Date data; //Métodos getter e setter ... } Listagem 3 - Classe de Domínio: DepartamentoCursos Observando a Listagem 1, vê-se que a tag <composite-id> mapeia a chave composta. O atributo name informa o atributo que mapeia a chave composta e o atributo class a classe de domínio, no caso br.com.j2eebrasil.dominio.DepartamentoCursoID. O corpo da tag é formado por duas outras tags <key-many-to-one> que informam os atributos da chave composta dentro da classe DepartamentoCursoID. Para exemplificar o relacionamento n-n com atributos, observe o exemplo da Listagem 4. Primeiro um departamento e um curso são buscados da base de dados, ambos com identificadores iguais a 1. Em seguida, cria-se uma instância de um objeto da classe DepartamentoCursoID que representa a chave composta. Os valores que compõem a chave, curso e departamento, são atribuídos. Finalmente, cria-se um objeto da classe DepartamentoCurso que representa a tabela de relacionamento entre as entidades, define-se a sua chave composta e a data de criação, persistindo-o na base de dados. ... Departamento d = (Departamento)session.get(Departament1.class, 1); Curso c = (Curso)session.get(Curso.class, 1); DepartamentoCursoID dcID = new DepartamentoCursoID(); dcID.setDepartamento(d); dcID.setCurso(c); DepartamentoCurso dc = new DepartamentoCurso(); dc.setCompositeID(dcID); dc.setData(new Date()); session.save(dc); ... Listagem 4 - Exemplo: Relacionamento n-n com atributos O resultado da execução do código presente na Listagem 4 pode ser visto na Listagem 5. Hibernate: select departamen0_.ID_DEPARTAMENTO as ID1_0_ from DEPARTAMENTO1 departamen0_ where departamen0_.ID_DEPARTAMENTO=? Hibernate: select curso1x0_.ID_CURSO as ID1_0_ from CURSO1 curso1x0_ where curso1x0_.ID_CURSO=? Hibernate: insert into DEPARTAMENTO_CURSO (data, ID_CURSO, ID_DEPARTAMENTO) values (?, ?, ?) Listagem 5 – Resultado da execução do código presente na Listagem 4 Associações 1-1 (one-to-one)Para exemplificar o relacionamento 1-1, considere o relacionamento na Figura 2 entre as entidades Universidade e Endereco, ou seja, uma universidade tem um único endereço e um endereço pertence apenas a uma única universidade.
Figura 2 - Relacionamenteo 1-1 entre Universidade e Endereco As Listagens 6 e 7 apresentam as classes Java para as entidades Universidade e Endereco, respectivamente. package br.com.j2eebrasil.dominio; public class Endereco implements Serializable{ private int id; private String rua; private int numero; private String bairro; private String cidade; private String uf; private int cep; private Universidade universidade; //Implementação dos métodos setter e getter ... } Listagem 6 – Classe de Domínio: Endereço package br.com.jeebrasil.dominio; import java.util.Collection; public class Universidade implements Serializable{ private int id; private String nome; private Endereco endereco; private Collection centros; //Implementação dos métodos setter e getter ... } Listagem 7 - Classe de Domínio: Universidade Existem duas formas de se mapear este relacionamento 1-1. A primeira estratégia é no mapeamento da entidade Universidade adicionar um mapeamento <many-to-one> para a tabela Endereco. O mapeamento da entidade Endereco é visto na Listagem 8 e não apresenta nenhuma novidade. ... <hibernate-mapping> <class name="br.com.j2eebrasil.dominio.Endereco" table="ENDERECO"> <id name="id" column="ID_ENDERECO" type="int"> <generator class="native"/> </id> <property name="rua"/> <property name="numero"/> <property name="bairro"/> <property name="cidade"/> <property name="uf"/> <property name="cep"/> </class> </hibernate-mapping> Listagem 8 - Endereco.hbm.xml Para realizar o mapeamento 1-1 de acordo com essa estratégia, basta inserir um mapeamento <many-to-one> no mapeamento da tabela Universidade (Listagem 7) como mostrado na Listagem 9. ... <many-to-one name="endereco" class="br.com.j2eebrasil.dominio.Endereco" column="ID_ENDERECO" cascade="save-update" unique="true"/> ... Listagem 9 – Relacionamento 1-1 em Universidade.hbm.xml: 1ª estratégia Veja que o atributo cascade foi definido como save-update o que implica em o objeto Endereco ser inserido ou atualizado automaticamente quando o objeto Universidade for inserido ou atualizado. Nesse mapeamento aparece o atributo unique, que quando assume valor true implica em ter apenas uma universidade por endereço. A outra abordagem é ao invés de inserir o código da Listagem, 9 no mapeamento de Universidade.hbm.xml, inserir o código mostrado na Listagem 10. A tag <one-to-one> define o relacionamento 1-1 que a classe Universidade tem com a classe Endereco. Os atributos desta tag não são novidades. ... <one-to-one name="endereco" class="br.com.j2eebrasil.dominio.Endereco" cascade="save-update"/> ... Listagem 10 - Relacionamento 1-1 em Universidade.hbm.xml: 2ª estratégia Para utilizar a tag <one-to-one> no arquivo Universidade.hbm.xml, o mapeamento do endereço em Endereco.hbm.xml deve ser feito como mostrado na Listagem 11. ... Listagem 11 - Relacionamento 1-1 em Endereco.hbm.xml: 2ª estratégia A primeira diferença para o mapeamento anterior da entidade Endereco é o valor do atributo class da tag generator agora é foreign. A tag param de name igual a property permite a associação 1-1 da classe Endereco com a classe Universidade, o que acontece é que um parâmetro é passado para a classe geradora do identificador, que neste caso é a propriedade universidade, que é da classe que se relaciona 1-1 com Endereco. A garantia de que um endereço pertença a uma única universidade vem do fato da chave primária da tabela ENDERECO (ID_UNIVERSIDADE) ser também a chave estrangeira que liga a Universidade. O mapeamento 1-1 em Endereco de Universidade também é feito utilizando a tag <one-to-one>. A única novidade da tag é o atributo constrained que sendo igual a true, implica em existir uma relação entre a chave primária de Endereco e de Universidade, informando ao Hibernate que um endereço não pode existir sem que uma universidade exista. ConclusõesNeste tutorial foram apresentados os mapeamentos de relacionamentos n-n com atributos e 1-1. O próximo módulo será referente ao mapeamento de coleções (Bag, Map, List, Set) usando o Hibernate.
Referências
|