Boas práticas com heranças no Hibernate

9 respostas
jpajavahibernate
A

Bom dia.

Eu tenho uma entidade Pessoa, que hoje ela está ligada com PessoaFisica e PessoaJuridica através de um mapeamento @OneToOne:

@OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private PessoaFisica pessoaFisica;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private PessoaJuridica pessoaJuridica;

E ainda essa classe Pessoa, ela pode ser um Cliente, Fornecedor, Transportadora, Vendedor ou vários deles ao mesmo tempo e hoje também estão mapeados como @OneToOne:

@OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private Cliente cliente;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "pessoa", orphanRemoval = true, fetch = FetchType.LAZY)
    private Fornecedor fornecedor;

As filhas estão compartilhando o id da Pessoa e utilizam um @MapsId. Dessa forma:

@Id
    @Column(name = "id", nullable = false)
    private Integer id;

    @MapsId
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "id")
    private Pessoa pessoa;

Qual seria a melhor maneira e mais elegante de se mapear estas classes, para que eu não tenha que cair no problema de Extra Queries, pois várias regras em meu Controller são executadas e aplicadas dependendo de cada uma dessas “relações” e gostaria de buscar e executar as queries apenas do que realmente vou trabalhar para a Pessoa em questão.

Obrigado.

9 Respostas

J

Cliente, Fornecedor, Transportadora e Vendedor são entidades diferentes. Particurlamente não faria essa mistura, só vai se complicar.

A

Então aqui criei como especialização de Pessoa.

Pessoa tem os campos principais e Cliente, Fornecedor e etc… complementam Pessoa.

Eu achei melhor do que ter uma tabela/entidade para cada uma dessas entidades, até porque no final das contas “são tudo pessoas” o que muda são particularidades para cada um.

Mas de qualquer forma, você sabe como eu poderia fazer essa implementação de herança de uma forma que fique evitando extra queries?

J

Isso é visão academica.

HQL

A

Certo.

Desculpe, acho que não estou conseguindo ser claro na dúvida.

Se Cliente, Vendedor, Transportadora e etc… são especializações de Pessoa, logo eles deveriam herdar Pessoa.

Minha dúvida é se há uma forma de fazer essa herança, sem adicionar extra queries? Vi algo sobre a anotação @Inheritance, mas fiquei na dúvida.

E se seria uma boa prática adicionar uma marcação na Pessoa, mesmo para PessoaJuridica/Fisica, pois o que não queria era ter que carregar a Pessoa e executar uma query para verificar se é Juridica e uma query para verificar se é Fisica ou mesmo já trazer ambos através do FETCH sendo que ele só pode ser uma delas.

J

Veja se a estratégia de usar um discriminador te ajuda: https://www.objectdb.com/api/java/jpa/DiscriminatorValue, assim deve retornar diretamente a partir do tipo específico.

A

Obrigado pela resposta

Entendi, isso ajudaria no caso da PessoaFisica e Juridica, mas pelo que olhei no Stack.

O Hibernate permite apenas uma estratégia de herança por entidade, correto?

Se eu precisar permitir a herança para o caso da PessoaFisica/PessoaJuridica que poderia ser através de um discriminador F ou J por exemplo e também fazer a herança para os child Cliente, Transportadora, Vendedor e Fornecedor, eu teria que mudar a estratégia, certo?

Para este tem alguma dica de como eu poderia aplicar?

J

Teriam discriminadores para todos que herdam de algo. Existem também outras estratégias que pode dar uma estudada: https://www.thoughts-on-java.org/complete-guide-inheritance-strategies-jpa-hibernate/

É até onde posso ajudar. Só não concordo com esse acoplamento todo, pois são responsabilidades diferentes.

A

Cara desculpa prolongar o tópico e talz.

Eu já até dei lida nesse link que passou e uns outros 200 rs.

Então você diz que eu poderia ter discriminadores para todas as heranças, por exemplo, eu teria um discriminador para PessoaFisica/Juridica F ou J.
E poderia ter um discriminador para Cliente, Transportadora, Fornecedor e Vendedor?
O único ponto é, uma Pessoa pode ser um ou mais deles, por exemplo, você pode ser Consumidor (Comprar meus produtos), mas ser fornecedor e me fornecer alguma matéria-prima, nesse caso eu teria que ter um discriminador para cada especialização?

Mas o ponto principal que ainda não consegui chegar, é que estou tentando reduzir as extra queries, pois estou fazendo uma refatoração no projeto, pois o antigo desenvolvedor colocou enable_lazy_load_no_trans no projeto e ele foi construído dessa maneira, tudo por padrão é EAGER agora estou corrigindo a performance e estou tentando reduzir.

Então o ponto é vou usar como exemplo apenas PessoaFisica e Juridica, hoje como a Pessoa pode ser um ou outro e eles estão @OneToOne, optional = true. Ambos são considerados na query através do LEFT JOIN.

Eu pensei em fazer essa relação de forma unidirecional onde eu carrego eles através do mapeamento de Pessoa neles e ai eu adicionaria um discriminador na Pessoa para saber quando carregar um ou outro, ao invés de fazer sempre LEFT JOIN em ambos, mas também vi o caso da Inheritance.

Então o que seria melhor em termos de performance:

  1. Carregar tudo na query principal através dos JOIN FETCH independente dele sempre ser um ou outro.

  2. Fazer a herança (O que eu vi no console que por baixo o que ele faz também são LEFT JOIN FETCH)

  3. Carregar a Pessoa, verificar no código se o discriminador é F ou J e baseado nisso executar uma outra Query para buscar apenas PessoaFisica ou apenas PessoaJuridica.

J

Em ambientes mais profissionais essa misturada toda não acontece. Seu cadastro como cliente em um site por exemplo não será o mesmo usado como fornecedor, são histórias diferentes para a pessoa.

Mas levando em consideração seu modelo de dados “técnico” com Pessoa, usaria composição ao invés de herança.

Criado 3 de maio de 2018
Ultima resposta 4 de mai. de 2018
Respostas 9
Participantes 2