Início > Análise > Estratégias de Mapeamento de Herança de Entidades

Estratégias de Mapeamento de Herança de Entidades

A normalização do banco de dados elimina a redundância dos dados e facilita as alterações nos schemas das tabelas. Entretanto, um schema normalizado implica em aumento dos joins, o que torna as queries mais lentas do que aquelas baseadas em modelos desnormalizados.

Quando se trabalha com ORM (Object Relational Mapping), não é possível fazer um modelo orientado a objetos ideal – com estado e comportamento centrados no objeto ao qual dizem respeito. Sempre será necessário ceder em alguns aspectos e esse é o grande desafio: criar um modelo que equilibre as boas práticas do modelo relacional e o poder do modelo orientado a objetos sem que seja necessário fazer muitos joins e tomando cuidado com table full scans. O ideal é normalizarmos o schema primeiro para só então ir desnormalizando de acordo com a necessida – cache, por exemplo.

Na JPA, entidades suportam hierarquia, associassões e queries polimórficas. Entidades podem extender classes que não são entidades e vice-versa e entidades podem ser abstratas ou concretas. Sabendo disso, vamos analisar as estratégias de mapeamento de hierarquia que a JPA oferece. Para uma comparação mais completa das vantagens e desvantagens de cada uma, visite [2].

Mapped Superclasses

Com essa estratégia, herda-se o mapeamento de colunas de uma classe concreta ou abstrata anotada com @MappedSuperclass que não é uma entidade, ou seja, não tem a anotação @Entity, não tem uma relação direta com uma tabela e por isso mesmo não pode ser utilizada em queries. É a entidade concreta que deve ser persistida.

@MappedSuperclass
public abstract class Pessoa {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_PESSOA")
   protected Integer id;
}

@Entity
@Table(name = "TBL_PESSOA_FISICA")
public class PessoaFisica extends Pessoa {
    @Column(name = "VL_SALARIO")
    private Float salario;
}

@Entity
@Table(name = "TBL_PESSOA_JURIDICA")
public class PessoaJuridica extends Pessoa {
    @Column(name = "VL_HORA")
    private Float valorHora;
}

Single Table per Class Hierarchy

É um tipo de estratégia horizontal, digamos assim, onde todos os atributos de todas as classes em uma hierarquia ficarão em uma mesma tabela diferenciando-se uma subclasse de outra por um atributo designador em uma coluna pré-determinada mapeada com a anotação @DiscriminatorColumn e cujo valor é identificado pena anotação @DiscriminatorValue.

Essa estratégia oferece um bom suporte a relacionamentos polimórficos entre entidades, mas deve-se tomar o cuidado de manter colunas que são específicas de uma entidade como nullable.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "IC_TIPO", length = 1, 
   discriminatorType = DiscriminatorType.STRING)
@Table(name = "TBL_PESSOA")
public class Pessoa {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_PESSOA")
   protected Integer id;

   @Column(name = "IC_TIPO", updatable=false)
   private String tipo;
}
 
@Entity
@DiscriminatorValue(value = "F")
public class PessoaFisica extends Pessoa {
    @Column(name = "VL_SALARIO")
    private Float salario;
}
 
@Entity
@DiscriminatorValue(value = "J")
public class PessoaJuridica extends Pessoa {
    @Column(name = "VL_HORA")
    private Float valorHora;
}

Table per Concrete Class

Nessa estratégia, o estado de cada classe concreta será armazenado em sua própria tabela e cada tabela é totalmente isolada das demais. Alguma relação só pode ser observada quando se analisa do ponto de vista das classes e não das tabelas. Dessa forma, o suporte a relacionamentos polimórficos é bem precário e é necessário realizar alguns SQL UNION para montar a entidade em sua hierarquia. Como o suporte a essa estratégia é opcional, verifique se o seu JPA Provider a implementa.

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Pessoa {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_PESSOA")
   protected Integer id;
}
  
@Entity
@Table(name = "TBL_PESSOA_FISICA")
public class PessoaFisica extends Pessoa {
    @Column(name = "VL_SALARIO")
    private Float salario;
}
  
@Entity
@Table(name = "TBL_PESSOA_JURIDICA")
public class PessoaJuridica extends Pessoa {
    @Column(name = "VL_HORA")
    private Float valorHora;
}

Joined Subclass

Essa estratégia também é chamada de mapeamento de hierarquia vertical, pois o estado da classe raiz é armazenado em uma tabela e cada subclasse terá sua própria tabela para armazenar os atributos que são específicos dela. Essas tabelas se relacionam com a tabela pai por uma coluna que armazena a chave da tabela pai. Comparando a hierarquia de classe ao relacionamento entre as tabelas geradas, observa-se que essa estratégia é a mais próxima do modelo de classes que a mapeia.

Ela fornece um bom suporte a relacionamentos polimórficos, mas para recuperar o estado persistente, deve-se realizar um ou mais SQL JOIN. Por isso, deve-se ter atenção a possíveis problemas de performance.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = “TBL_PESSOA”)
public abstract class Pessoa {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_PESSOA")
   protected Integer id;
}
  
@Entity
@Table(name = "TBL_PESSOA_FISICA")
@PrimaryKeyJoinColumn(name="PK_PESSOA_FISICA", referencedColumnName="PK_PESSOA")
public class PessoaFisica extends Pessoa {
    @Column(name = "VL_SALARIO")
    private Float salario;
}
  
@Entity
@Table(name = "TBL_PESSOA_JURIDICA")
@PrimaryKeyJoinColumn(name="PK_PESSOA_JURIDICA", referencedColumnName="PK_PESSOA")
public class PessoaJuridica extends Pessoa {
    @Column(name = "VL_HORA")
    private Float valorHora;
}

Referências

1. [https://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html]

2. [http://docs.oracle.com/html/E13946_06/ejb3_overview_mapping_inher.html]

3. [http://www.devmedia.com.br/tipos-de-heranca-no-hibernate/28641]

4. [http://stackoverflow.com/questions/3557879/hibernate-and-inheritance-table-per-class]

5. [http://stackoverflow.com/questions/8162233/table-per-subclass-vs-table-per-concrete-class-in-hibernate]

6. [https://blogs.oracle.com/carolmcdonald/entry/jpa_performance_don_t_ignore]

7. [http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/jpa_overview_mapping_inher.html]

Anúncios
  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: