Boas práticas com heranças no Hibernate

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.

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

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?

Isso é visão academica.

HQL

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.

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.

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?

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.

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.

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.