Skip to content


Mapeando herança no Hibernate 3

Quando estamos desenvolvendo um sistema, partimos para uma estratégia simples de mapeamento, ou seja: uma tabela para cada entidade mapeada de classe. E isso funciona muito bem. O problema começa quando pensamos em Orientação a Objetos e, falamos em herança.

Como eu disse, herança tem a ver com Orientação a Objetos e os bancos de dados relacionais – baseados em SQL – não são. Tente entender assim, nos modelos orientados a objetos nós temos as relações tem-um e é-um. Enquanto que nos banco de dados relacionais temos apenas a relação tem-um. Os bancos de dados relacionais não suportam a relação de herança e, mesmo quando suportam, são prioritários ou incompletos.

O objetivo deste post é demonstrar um dos possíveis mapeamentos de herança. Como foi dito, os bancos de dados relacionais não suportam herança, porém, o JPA nos fornece maneiras de implementar esta funcionalidade através de uma foreign-key.

Assim cada classe terá sua própria tabela, e se relacionará com a classe pai através da sua chave estrangeira.

Primeiramente vamos criar um cenário para testar nosso aplicativo de exemplo. Vamos supor que temos uma classe Pessoa que represente uma pessoa comum e uma classe Usuário que estenda Pessoa, ou seja, um usuário é uma pessoa, porém com alguma especialidade, por exemplo, um login.

Em Pessoa precisamos dizer que ela é uma classe pai na hierarquia de herança. Fazemos isso anotando-a com @Inheritance. Ainda é preciso definir a estratégia com que a herança será feita, no nosso caso usaremos InheritanceType.JOINED, pois queremos que a herança seja feita através da junção (através de uma foreign key) da(s) tabela(s) filha(s) com a tabela pai.

Na classe filha, precisamos apenas dizer qual é a coluna da tabela que fará o join com a tabela pai. Isso é feito com a anotação @PrimaryKeyJoinColumn(name=”pessoa_id”), onde o “pessoa_id” é o atributo da tabela filha que fará referencia a tabela pai.

Tudo pronto agora. Sempre que você inserir um objeto Usuario o objeto Pessoa será persistido automaticamente. A saída abaixo ilustra o que o Hibernate gera para inserir um Usuário (o id da Pessoa está como auto-incremento na tabela).

Hibernate: insert into Pessoa (nome) values (‘Normandes’)

Hibernate: insert into Usuario (login, pessoa_id) values (‘junior, 1)

Apesar de este método ser fácil às vezes pode não ser muito eficiente, pois sempre que você fizer uma busca em Pessoa o Hibernate fará um join com Usuário. E, caso existam 10 classes filhas, se uma busca for feita na classe pai serão feitos 10 joins com as classes filhas.

Mesmo com esta desvantagem acho interessante o uso em sistemas menores. Isto torna a modelagem elegante.

Quem quiser pode testar pegando o código fonte aqui.

Abraços.

Posted in Hibernate, Java.

Tagged with , , , .


7 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Marcos says

    Olá,

    .. “E, caso existam 10 classes filhas, se uma busca for feita na classe pai serão feitos 10 joins com as classes filhas.” ..

    Essa desvantagem é facilmente contornada, fazendo bom uso da Herança, por exemplo, em muitos casos, trocando-a para Composição. No seu exemplo, Usuario é uma Pessoa, o que está correto o uso da herança, mas em muitos outros casos, Composição é recomendado.

    Com o bom senso, e balanceando o uso de cada um deles, você mantém poucos JOINS e cria, como você mesmo falou a modelagem elegante, e acrescento:

    - Fica mais fácil manter
    - Fica melhor de entender
    - Fica mais fácil extender (criar novas classes (e tabelas))
    - Entre outros milhões de fatores ..

    Parabéns pelo post!

    Saudações

  2. Normandes Junior says

    Olá Marcos,

    Concordo 100% com você. O uso da herança deve ser analisado com cautela! Devemos lembrar que ela diminui o encapsulamento.

    Este post serve de ilustração para pessoas que realmente querem utilizar da herança para fazer um mapeamento.

    Obrigado pelo comentário. Abraços.

  3. André de Souza says

    Ola Pessoal, tambem estou usando herança com hibernate da maneira como foi explicado acima, com a diferença de que optei pelo metodo Table_Per_Class que faz com que cada classe filha tenha uma tabela independente da classe pai, com uma foreign key para relacionar elas, ate ai tudo bem, o problema começa quando vou inserir um usuario, que é uma pessoa, como eu faço para inserir ele no banco? visto que meu usuario so tem os metodos setSenha e setUsuario, e os gets é claro, como setar os outros atributos como nome, que ja fazem parte da classe pessoa? obrigado pessoal, agradeço desde ja a boa vontade em ajudar, obrigado

  4. Normandes Junior says

    André, como Usuário extende Pessoa ele irá herdar os métodos setters e gettes da classe Pessoa. Portanto você irá poder fazer:
    Usuario u = new Usuario();
    u.setLogin(”usr”);
    u.setPwd(”123″);
    u.setNome(”SeuNome”);

    Acredito que é esta sua dúvida. Se não for, tente mostrar o código das suas classes.

  5. lucimara says

    Ótimo post… vlw pela ajuda!!!

  6. Sérgio says

    Olá pessoal, seguindo o que você explicou e o o exemplo consegui inserir os dados na tabela usando o campo com auto incremento, coisa que já faz uma semana que estou tentando. O problema é que tenho a classe PojoGenerico onde está o id e a classe referencia que estende dela. no meu banco tem a tabela referencia. Porém quando insiro ele cria a tabela pojogenerico só com o campo dessa classe. Tem como fazer com que ele nao crie essa tabela? Obrigado pela ajuda.

  7. Normandes Junior says

    Não entendi a sua dúvida Sérgio. Tente mandar mais informações.



Some HTML is OK

or, reply to this post via trackback.