Mapeando Herança com Hibernatepor: Raphaela Galhardo (raphaela@jeebrasil.com.br) Neste tutorial serão abordados os mapeamentos de herança com Hibernate para as três tipos de estratégias: tabela por classe concreta, tabela por hierarquia e tabela por sub-classe. IntroduçãoO Hibernate fornece vários mecanismos de se realizar o mapeamento de uma relação de herança:
Neste tutorial serão abordados os mapeamentos de herança para as três estratégias descritas acima. Mapeamento de HerançaObserve o exemplo de herança apresentado na Figura 1. Neste caso, as classes Aluno e Professor herdam da classe Pessoa, ou seja, são seus filhos.
Figura 1 - Exemplo de Herança As Figuras 2, 3 e 4 mostram as tabelas que devem ser criadas para as estratégias de mapeamento tabela por classe concreta, tabela por hierarquia e tabela por subclasse, respectivamente.
Figura 2 - Tabela por Classe Concreta
Figura 3 - Tabela por Hierarquia
Figura 4 - Tabela por Sub-Classe Em relação à estratégia tabela por classe concreta, o mapeamento deve ser feito aplicando os conhecimentos já estudados em tutoriais anteriores, pois existem duas tabelas independentes. O principal problema dessa estratégia é que não suporta muito bem associações polimórficas. Em banco de dados, as associações são feitas através de relacionamentos de chave estrangeira. Neste caso, as subclasses são mapeadas em tabelas diferentes, portanto uma associação polimórfica para a classe mãe não seria possível através de chave estrangeira. Outro problema conceitual é que várias colunas diferentes de tabelas distintas compartilham da mesma semântica, podendo tornar a evolução do esquema mais complexo, por exemplo, a mudança de um tipo de uma coluna da classe mãe implica em mudanças nas várias tabelas mapeadas. Em relação à tabela por hierarquia, o mapeamento deve ser feito como mostrado na Listagem 1. O mapeamento da classe Pessoa é feito para a tabela PESSOA. Para haver a distinção entre as três classes (Pessoa, Aluno e Professor) surge uma coluna especial (discriminator). Essa coluna não é uma propriedade da classe persistente, mas apenas usada internamente pelo Hibernate. No caso, a coluna discriminator é a TIPO_PESSOA e neste exemplo pode assumir os valores 1 e 2. Esses valores são atribuídos automaticamente pelo Hibernate. Cada subclasse possui uma tag <subclass>, onde suas propriedades devem ser mapeadas. ... <hibernate-mapping> <class name="br.com.j2eebrasil.dominio.Pessoa" table="PESSOA" discriminator-value="0"> <id name="id" column="ID_PESSOA" type="int"> <generator class="sequence"> <param name="sequence">pessoa_seq</param> </generator> </id> <!-- Coluna Discriminante --> <discriminator column="TIPO_PESSOA" type="int"/> <!-- Propriedades comuns --> <property name="matricula"/> <property name="nome"/> <property name="cpf"/> <!-- Subclasse Aluno --> <subclass name="br.com.j2eebrasil.dominio.Aluno" discriminator-value="1"> <many-to-one name="curso" column="ID_CURSO" class="br.com.j2eebrasil.dominio.Curso"/> </subclass> <!-- Subclasse Professor --> <subclass name="br.com.j2eebrasil.dominio.Professor" discriminator-value="2"> <many-to-one name="departamento" column="ID_DEPARTAMENTO" class="br.com.j2eebrasil.dominio.Departamento"/> </subclass> </class> </hibernate-mapping> Listagem 1 - Mapeamento Herança: Tabela por Hierarquia A estratégia tabela por hierarquia é bastante simples e apresenta o melhor desempenho na representação do polimorfismo. É importante saber que restrições não nulas não são permitidas para o mapeamento de propriedades das subclasses, pois esse mesmo atributo para uma outra subclasse será nulo. A terceira estratégia, como já citada, consiste em mapear cada classe em uma tabela diferente. Para o exemplo citado, essa estratégia de mapeamento pode ser vista na Listagem 2. Nessa estratégia as tabelas filhas contêm apenas colunas que não são herdadas e suas chaves primárias são também chaves estrangeiras para a tabela mãe. ... <hibernate-mapping> <class name="br.com.j2eebrasil.dominio.Pessoa" table="PESSOA"> <id name="id" column="ID_PESSOA" type="int"> <generator class="increment"/> </id> <!-- Propriedades comuns --> <property name="matricula"/> <property name="nome"/> <property name="cpf"/> <!--Sub-Classe Aluno --> <joined-subclass name="br.com.j2eebrasil.dominio.Aluno" table="ALUNO"> <key column="ID_ALUNO"/> <many-to-one name="curso" column="ID_CURSO" class="br.com.j2eebrasil.dominio.Curso"/> </joined-subclass> <!--Sub-Classe Professor --> <joined-subclass name="br.com.j2eebrasil.dominio.Professor" table="PROFESSOR"> <key column="ID_PROFESSOR"/> <many-to-one name="departamento" column="ID_DEPARTAMENTO" class="br.com.j2eebrasil.dominio.Departamento"/> </joined-subclass> </class> </hibernate-mapping> Listagem 2 - Mapeamento Herança: Tabela por Sub-Classe Neste caso, por exemplo, se um objeto da classe Aluno é persistido, os valores das propriedades da classe mãe são persistidos em uma linha da tabela PESSOA e apenas os valores correspondentes à classe Aluno são persistidos em uma linha da tabela ALUNO. Em momentos posteriores essa instância de aluno persistida pode ser recuperada de um join entre a tabela filha e a tabela mãe. Uma grande vantagem dessa estratégia é que o modelo de relacionamento é totalmente normalizado. Observe que no mapeamento, o Hibernate utiliza a tag <joined-class> para realizar o mapeamento por subclasse. A tag key declara as chaves primárias das subclasses que são também chaves estrangeiras para a chave primária da classe mãe. ConclusõesNeste tutorial foi apresentado o mapeamento de herança com Hibernate utilizando três estratégias distintas. A escolha da estratégia vai depender dos requisitos exigidos pela aplicação. O próximo apresenta conceitos relacionados a transações e como ela é implementada com Hibernate. Referências
|