Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Criação de Classes e Entidades JPA

Olá,

Estou com a seguinte dúvida/problema: Pensando em uma aplicação para gerenciar hospedagens de um hotel, eu estou criando as classe de clientes/hóspede. Pensando no futuro, imagine que um cliente se hospeda e no check-out ele pede a missão de uma nota fiscal, se ele for pessoa física o sistema consegue emitir uma nf no cpf dele por exemplo, mas se ele for funcionário de uma empresa e quer que a nf seja emitida para o cnpj da empresa? Pensando nisso, eu idealizei o projeto das classes de clientes da forma abaixo:

!Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Então eu criei uma classe abstrata chamada Cliente, que tem um atributo ID e um método faturar(). Criei as classes PessoaFisica e PessoaJurídica, as duas extendem a clesse cliente, pois compartilham de um atributo em comum(ID) e ambas podem ser faturados. Já a classe PessoaFísica implementa a interface Hospedável que tem o método hospedar(), pois é o único tipo de cliente que poderá popular uma tabela "hospedagem" no futuro.

A grande pergunta é: Como fazer para a JPA entender que o atributo ID é herdado da classe abstrata Cliente? Como será a representação na base de dados? Serão 3 tabelas (clientes, pessjoa_juridica, pessoa_fisica) ou será uma tabela só, tipo clientes, com os atributos das duas tabelas?

Outra coisa que estou pensando aqui, é o seguinte: Vou criar as entidades Endereço e Telefone, mas caso a JPA crie duas tabelas para os clientes (tipo pessoa_fisica e pessoa_juridica) vou ter problemas com as entidades Endereço e Telefone no banco de dados pois podem ter clientes com o mesmo id, tipo: se no campo "id_cliente" da tabela endereço tiver preenchido com o valor 1, esse valor pode ser de uma pessoa física ou de uma pessoa jurídica, aí vou ter problema de inconsistência de dados.

Como lidar com essas duas situações?

Agradeço desdejá.

2 respostas
solução!

Olá Damião, tudo bem com você?

1- Sobre a herança na JPA: A JPA suporta diferentes estratégias para mapear herança de classes para tabelas de banco de dados. As três estratégias principais são: SINGLE_TABLE, JOINED e TABLE_PER_CLASS.

  • SINGLE_TABLE: Nesta estratégia, todas as classes da hierarquia são mapeadas para uma única tabela no banco de dados. A tabela tem uma coluna discriminante para identificar qual classe uma linha representa. Neste caso, teríamos uma tabela "cliente" com todos os atributos de "PessoaFisica" e "PessoaJuridica", e um campo adicional para identificar o tipo de cliente.

  • JOINED: Nesta estratégia, cada classe tem sua própria tabela, e um join é feito para recuperar uma entidade completa. Ou seja, teríamos uma tabela "cliente", uma tabela "PessoaFisica" e uma tabela "PessoaJuridica". As tabelas de "PessoaFisica" e "PessoaJuridica" teriam uma chave estrangeira referenciando a tabela "cliente".

  • TABLE_PER_CLASS: Nesta estratégia, cada classe tem sua própria tabela, mas não há tabela para a classe abstrata. Ou seja, teríamos uma tabela "PessoaFisica" e uma tabela "PessoaJuridica", ambas com o campo "id".

2- Sobre a questão do ID: Se você optar pela estratégia JOINED ou SINGLE_TABLE, não haverá problemas com IDs duplicados, pois a JPA garante que o ID seja único em toda a hierarquia de classes. Se você optar pela estratégia TABLE_PER_CLASS, então você precisa garantir que os IDs sejam únicos em todas as tabelas.

3 - Sobre as entidades "Endereço" e "Telefone": Você pode criar uma relação de um para muitos entre "Cliente" e "Endereço" e "Telefone". Assim, cada cliente pode ter vários endereços e telefones, e cada endereço e telefone pertence a um único cliente. Para fazer isso, você pode usar a anotação @OneToMany em sua classe "Cliente". Por exemplo:

@Entity
public class Cliente {
    @OneToMany(mappedBy = "cliente")
    private List<Endereco> enderecos;
    
    @OneToMany(mappedBy = "cliente")
    private List<Telefone> telefones;
    //...
}

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Obrigado Armano Barros Alves Junior!

Depois de ter quebrado a cabeça por algum tempo, resolvi deixar a Classe abstrata apenas como referência(não a tornei visível para a JPA através da anotação @Entity) e criei as duas entidades PessoaFísica e PessoaJuridica, o que é compatível com a estratégia TABLE_PER_CLASS que você descreveu.

Com relação a entidade Endereço e Telefone, em ambas, eu criei os atributos pfId e pjId ( que correspondem às colunas pessoafisica_id e pessoajuridica_id respectivamente). Quando eu criei a tabela endereço pela migration, informei que essas colunas receberão por padrão o valor 0 (DEFAULT 0). Caso o cliente seja PJ a coluna pessajuridica_id será preenchida com o id de cliente_pj e a coluna pessoafisica_id ficara com o valor 0.

CREATE TABLE enderecos (
                id BIGINT AUTO_INCREMENT NOT NULL,
                cep VARCHAR(8) NOT NULL,
                logradouro VARCHAR(100) NOT NULL,
                numero VARCHAR(100) NOT NULL,
                complemento VARCHAR(100) NOT NULL,
                bairro VARCHAR(100) NOT NULL,
                cidade VARCHAR(100) NOT NULL,
                estado VARCHAR(100) NOT NULL,
                pessoafisica_id BIGINT DEFAULT 0 NOT NULL,
                pessoajuridica_id BIGINT DEFAULT 0 NOT NULL,
                PRIMARY KEY(ID),
                constraint fk_enderecos_pessoafisica_id foreign key(pessoafisica_id) references clientes_pf(id),
                constraint fk_enderecos_pessoajuridica_id foreign key(pessoajuridica_id) references clientes_pj(id)
);

Aí eu consigo identificar quando um endereço ou telefone é de um cliente PJ ou PF.

Não sei se o que eu fiz está de acordo com as boas práticas, mas funcionou. As quaro tabelas foram criadas no banco(clientes_pj, clientes_pf, enderecos, telefones) e agora vou testar a inserção de dados para ver como fica.

Grato pela ajuda!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software