Tipos de Heranca no Hibernate

Veja neste artigo os tipos diferentes de herança que o Hibernate pode implementar.

Quando se trata de herança o Hibernate trata deste assunto muito bem e com eficácia, diga-se de passagem. Ocorre que não há apenas 1 método para realizar a Herança de classes no Hibernate, o que confunde a maioria dos desenvolvedores. Antes de dar início é importante salientar que o uso inapropriado de herança no Hibernate pode causar uma lentidão incalculável na sua aplicação, por isso pense se a melhor alternativa é composição ou herança.

Enfim, nosso foco não é mostrar se o melhor é composição ou herança, mas sim as formas de se implementar uma herança no Hibernate. Estas formas são 3:

Cada uma dessas tem sua peculiaridade, e não podemos simplesmente dizer: A solução X é melhor que Y, pois isso depende de inúmeras variáveis, tais como: suas regras de negócio.

Tabela Única por Hierarquia de Classes

Este é o famoso “tabelão” com milhares de campos, onde é gerado 1 tabela para toda a hierarquia de classes. Se você tiver uma Classe Pessoa como Superclasse, e outras 2 classes PessoaFisica e PessoaJuridica estendendo de Pessoa, o Hibernate irá gerar apenas 1 tabela Pessoa com os dados de Pessoa + PessoaFisica + PessoaJuridica.

E como é feita a divisão de quem é Pessoa Física e quem é Pessoa Jurídica ? Através de um atributo chamado discriminator. No seu “tabelão” deverá ter um campo que faça a discriminação entre PessoaFisica (F) e PessoaJuridica (J). Veja abaixo na listagem 1 a implementação da classe Pessoa.

Listagem 1: mplementação da Classe Pessoa

@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "tipo", length = 1, discriminatorType = DiscriminatorType.STRING) @DiscriminatorValue("P") public class Pessoa implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long idPessoa; private String nome; @Column(insertable=false, updatable=false) private String tipo; //getters and setters omitidos }

O que vai nos importar no código acima são 3 linhas:

  1. @Inheritance(strategy = InheritanceType.SINGLE_TABLE): Identifica que a estratégia de herança será de uma única tabela, ou se preferir, um “tabelão” para tudo.
  2. @DiscriminatorColumn(name = "tipo", length = 1, discriminatorType = DiscriminatorType.STRING): Identifica que o campo que armazenará o discriminator é o “tipo”, de tamanho 1, do tipo String.
  3. @DiscriminatorValue("P"): Identifica que a Classe Pessoa será identifica com o atributo “P” na tabela Pessoa, ou seja, onde tiver “P” é porque aquele registro é uma pessoa.

Vamos ver agora na listagem 2 a implementação da pessoa física:

Listagem 2: Implementação da Pessoa Física

@Entity @DiscriminatorValue(value = "F") public class PessoaFisica extends Pessoa { private String cpf; //getters and setters omitidos }

Bem simples, o que nos interessa saber é que seu DiscriminatorValue é “F”, ou seja, onde tiver um “F” no campo tipo da tabela, significa que é uma Pessoa Física.

Listagem 3: Implementação da Pessoa Jurídica

@Entity @DiscriminatorValue(value = "J") public class PessoaJuridica extends Pessoa { private String cnpj; //getters and setters omitidos }

Dispensa explicações, mas é importante ser redundante para fixação do conteúdo. Onde tiver o valor “J” no campo tipo, significa que é uma Pessoa Jurídica.

Na figura 1, veja qual será o resultado da tabela:


Figura 1: Tabela Única por Hierarquia de Classes

Tabela por Subclasse

Nessa estratégia nós teremos a Classe Pai e todas suas filhas geradas no banco de dados fisicamente, sendo que em todas as classes filhas teremos uma chave estrangeira que apontará para a classe pai.

Isto é, se tivermos 1 Classe Pessoa com 5 atributos, 1 Classe Pessoa Física com 10 atributos e 1 Classe Pessoa Jurídica com 15 atributos, o gerado será: 1 tabela pessoa com 5 atributos, 1 tabela pessoa_fisica com 10 atributos e 1 tabela pessoa_juridica com 15 atributos. Vamos a exemplos.

Listagem 4: Implementação da Pessoa

@Entity @Inheritance(strategy = InheritanceType.JOINED) public class Pessoa implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long idPessoa; private String nome; //getters and setters omitidos }

A linha que nos interessa aqui é:

@Inheritance(strategy = InheritanceType.JOINED): Identifica que a estratégia de herança será “JOINED”, ou seja, será feita uma junção através de chaves estrangeiras.

Listagem 5. Implementação PessoaFisica @Entity @PrimaryKeyJoinColumn(name="idPessoa") public class PessoaFisica extends Pessoa { private String cpf; //getters and setters omitidos }

A linha importante aqui é:

@PrimaryKeyJoinColumn(name="idPessoa"): Identifica qual campo fará essa “junção” entre a tabela pessoa_fisica e a tabela pessoa.

Listagem 6: Implementação PessoaJuridica

@Entity @PrimaryKeyJoinColumn(name="idPessoa") public class PessoaJuridica extends Pessoa { private String cnpj; //getters and setters omitidos }

Este código acima segue a mesma lógica da Listagem 5, a coluna idPessoa faz a “junção” entre a tabela pessoa e a tabela pessoa_juridica. Veja como ficou as tabelas geradas.


Figura 2: Tabela por Subclasse

Tabela por Classe Concreta

Não menos importante, essa estratégia define que apenas as classes concretas geram suas respectivas tabelas, ou seja, em nosso exemplo apenas pessoaFisica e pessoaJuridica criarão tabelas, isso porque pessoa é uma classe abstrata.

Listagem 7: Implementação de Pessoa

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Pessoa implements Serializable { @Id private Long idPessoa; private String nome; //getters and setters omitidos }

A nossa estratégia agora é “TABLE_PER_CLASS”, que identifica que apenas as classes concretas serão geradas.

Listagem 8: Implementação PessoaFisica

@Entity public class PessoaFisica extends Pessoa { private String cpf; //getters and setters omitidos }

Nada de diferente aqui já que a estratégia é TABLE_PER_CLASS.

Listagem 9: Implementação PessoaJuridica

@Entity public class PessoaJuridica extends Pessoa { private String cnpj; //getters and setters omitidos }

Ainda nada de novo. Enfim, o resultado da sua tabela será visto na figura 3:


Figura 3: Tabela por Classe Concreta

CONCLUSÃO

Vimos neste artigo 3 tipos de estratégia de herança no Hibernate: SINGLE_TABLE, JOINED e TABLE_PER_CLASS. Cada um com sua peculiaridade e seus prós e contras. É difícil definir qual é o melhor, pois não há melhor, o melhor é você saber definir quando usar cada um destes.

Artigos relacionados