JPA/Hibernate e herança: os contras

  Olá, pessoal! Dando continuidade a série de dicas sobre JPA/Hibernate, vamos falar hoje um pouco dos cuidados ao...

Dextra

View posts by Dextra
Somos especialistas em desenvolvimento de software sob medida para negócios digitais. Pioneiros na adoção de metodologias de gestão ágil, combinamos processos de design, UX, novas tecnologias e visão de negócio, desenvolvendo soluções que criam oportunidades para nossos clientes. A Dextra faz parte da Mutant, empresa B2B líder no mercado brasileiro e especialista em Customer Experience para plataformas digitais.
Data de publicação: 05/12/2013


 
Olá, pessoal!
Dando continuidade a série de dicas sobre JPA/Hibernate, vamos falar hoje um pouco dos cuidados ao optar por utilizar herança entre entidades do JPA/Hibernate.


Apenas para contextualizar, o Hibernate oferece os seguintes tipos de estratégia para herança:

  • Single table
  • Joined
  • Table per class

Neste texto, vou especificamente do tipo de herança JOINED, com um caso comum de mapeamento de entidades.
Para apresentar os contras desta opção, vamos a um exemplo que deixará mais claro o entendimento. Considere as entidades Pessoa, PessoaFisica e PessoaJuridica:


Neste exemplo, podemos dizer que o sistema pode cadastrar as entidades PessoaFisica ou PessoaJuridica, sendo que ambas compartilham atributos da entidade Pessoa. Nesta configuração, teremos 3 tabelas: Pessoa, PessoaJuridica e PessoaFisica.
Se o sistema realizar uma pesquisa simples por PessoaFisica, usando o JPQL:

Teremos um SQL gerado pelo Hibernate e passado para o banco parecido com este (estou abstraindo os alias que o hibernate aplica para cada coluna das tabelas envolvidas):

Vamos observar o SQL. O Hibernate faz este JOIN de PessoaFisica com Pessoa pois ele tem certeza que a tabela PessoaFisica terá um registro correspondente em Pessoa. Naturalmente, o mesmo ocorrerá se pesquisar por uma PessoaJuridica.
Agora, vamos imaginar que temos uma tela que pesquisa por informações de Pessoa, independente se é PessoaJuridica ou PessoaFisica. No JPQL fazemos:

Agora chegamos no ponto interessante da discussão. Como será o SQL gerado pelo Hibernate? Veja:

Podemos observar 2 vezes a ocorrência de LEFT JOIN. Como uma Pessoa é necessariamente uma PessoaFisica ou PessoaJuridica, o Hibernate vai tentar criar a instância correta da classe no Java. Assim, por exemplo, se o desenvolvedor quiser fazer um “cast” de Pessoa (que foi retornada) para PessoaJuridica, sendo esta Pessoa uma PessoaJuridica, irá conseguir.
Este bônus de facilidade e transparência acaba também tendo os seus ônus, nos quais podemos destacar:

  • JOINs desnecessários no SQL, conforme observado no SQL anterior.
  • Se a entidade Pessoa, PessoaJuridica ou PessoaFisica tiver relacionamento EAGER com outras entidades, eles também serão acrescentados aos JOINs do SQL gerado. Mais um motivo para não usarmos EAGER.
  • Retorno de todas as informações das entidades envolvidas no SQL e não apenas de Pessoa.
  • Este problema fica mais grave com novas entidades estendendo Pessoa.

Embora faça certo sentido o Hibernate resolver desta maneira, os efeitos colaterais podem impactar negativamente na performance. O ideal era o Hibernate, tal como podemos fazer com relacionamentos, configurar um Proxy para resolver de forma LAZY esta situação, não precisando sempre fazer os JOINs e também retornar na consulta as informações das tabelas PessoaFisica e PessoaJuridica. Mas, tecnicamente isto é inviável.
A alternativa de mapeamento para este caso, onde desejamos criar um relacionamento de herança entre classes Java, é a mesma que a maioria dos desenvolvedores hoje defendem: usar composição ao invés de herança. Além das vantagens já conhecidas desta abordagem, no JPA/Hibernate temos uma simplificação do mapeamento sem as desavantagens citadas anteriormente.
Se a refatoração do mapeamento não for uma opção no momento e existirem problemas de performance, isto pode ser localmente resolvido se, ao invés de retornar a entidade Pessoa, retornar apenas os atributos desejados na consulta, conforme comentado em outro texto do blog da Dextra. Desta forma, o SQL gerado não realizará os LEFT JOINs e, naturalmente, nem retornar todos os atributos.
Agradecimentos ao Tiago Bento pela revisão do texto.
 

Dextra

View posts by Dextra
Somos especialistas em desenvolvimento de software sob medida para negócios digitais. Pioneiros na adoção de metodologias de gestão ágil, combinamos processos de design, UX, novas tecnologias e visão de negócio, desenvolvendo soluções que criam oportunidades para nossos clientes. A Dextra faz parte da Mutant, empresa B2B líder no mercado brasileiro e especialista em Customer Experience para plataformas digitais.

Comentários

  1. Ricardo24 de junho de 2019

    Olá Bom dia, já li diversos artigos falando sobre herança com JPA e o conselho é sempre o mesmo, usar composição no lugar de herança, entretando os mesmos artigos nunca mostram um exemplo prático de como fazer isso. Como por exemplo poderiamos mapear esse mesmo tipo de mapeamento descrito na mesma situação do exemplo acima envolvendo pessoa física e pessoa jurídica?

    Responder

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

vinte + vinte =

Posts relacionados

  1. Sobre a Dextra

    Somos especialistas em desenvolvimento de software sob medida para negócios digitais. Pioneiros na adoção de metodologias de gestão ágil, combinamos processos de design, UX, novas tecnologias e visão de negócio, desenvolvendo soluções que criam oportunidades para nossos clientes.

  2. Categorias

Scroll to top