Implementação de JPA com Herança

7 respostas
java
wladyband

Tenho tido um pouco de dificuldade para criar um projeto em Java, pois existe a necessidade de implementar herança nas minhas tabelas como por exemplo, estou criando um sistema para administração de condomínio, existe a tabela Condomino, Sindico, Morador e Proprietario.

O Sindico, Morador e Proprietario são um tipo de Condomino, porque eu sei que se tivesse que colocar os mesmos atributos que estão em Condomino e colocasse em Sindico, Morador e Proprietario ficaria redundante, é por isso que coloquei Condomino como Super-Class e as classes Sindico, Morador e Proprietario como Sub-Classe, ou seja, Condomino irá ser abstrata e as outras classes abaixo iram herdar os atributos da classe Condomino.

Sei abstrair tudo isso muito bem em UML, e também sei fazer isso em Java, em todas as classes coloquei as anotações do JPA como por exemplo do @NotBlank, e somente coloquei a anotação @Id, @GeneratedValue nas Sub-Classes porque a classe Condomino é uma classe abstrata.

A outra coisa que fiz foi somente colocar @Entity nas Sub-Classes pelo mesmo motivo da classe Condomino ser uma classe abstrata.

Pelo que fui informado de outros forúns de Java, normalmente nestes casos é utilizamos Agregação e não Herança. As implementações do JPA como o Hibernate não lidam muito bem com Herança. Na prática, ficaria algo assim:

public class Condomino {
    // atributos omitidos
}

public class Sindico {
    // atributos omitidos

    @ManyToOne
    @JoinColumn(name = "condomino_id")
    private Condomino condomino;
}

Eu gostaria de saber se realmente o JPA não sabe lidar com Herança e se eu fosse implementar herança no JPA que tipos de problemas eu poderia encontrar na frente?

7 Respostas

N

Existe mesmo?

Não faz sentido O Sindico, Morador e Proprietario ser um Condonomio. Você é um Condominio ou um Pessoa?

Mas já que vc mencionou isso:

Que tal um enum?

Teríamos a seguinte perspectiva de modelagem para o seu problema:

public enum PessoaTipo {
   SINDICO, MORADOR, PROPIETARIO;
}

public class Pessoa {
   //atributos Nome, etc...
   PessoaTipo  tipo;
}

Nada de herança. Ficou melhor, concorda ou discorda?

Essa é uma solução, isso implica que não é a única, nem a melhor, pode ser até pior que a sua idea.

Outra solução seria criar uma classe Pessoa(ou o nome que achar melhor que defina essa abstração) e definir como Embeaddable, veja como funciona: https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection

No exemplo do link acima, pense que Phone é Pessoa e Employee seria Morador.

Ajudou?

wladyband

ajudou bastante. show de bola :slight_smile:

wladyband

Vamos com calma, Condomino irá ter os seguintes atributos email, nome , idade data de nascimento, as outras entidade como sindico, proprietario e morador também terão esses atributos, porém alem de ter os atributos que a classe condomino irá ter a tabela sindico terá o atributos FimdoMandato e InicioMandato, a tabela morador terá InicioAluguel, TaxaAjuste e proprietario terá Datacompra, então cada entidade terá alguns atributos diferente, é por isso que pensei em Condomino ser uma classe abstrata.

Lucas_Camara

@norbAns, @wladyband quis dizer que Síndico, Morador e Proprietário são Condôminos, ou seja, co-proprietários do condomínio, e não o Condomínio propriamente dito.

Lucas_Camara

@wladyband, sua definição está correta, mas tem uns poréns:

A outra coisa que fiz foi somente colocar @Entity nas Sub-Classes pelo mesmo motivo da classe Condomino ser uma classe abstrata.

Você deve mapear a classe abstrata com @entity também. Afinal, ela também será uma tabela no banco.

e somente coloquei a anotação @Id, @GeneratedValue nas Sub-Classes porque a classe Condomino é uma classe abstrata.

O @Id e @GeneratedValue somente será colocado na classe abstrata, pois as filhas irão herdar esse atributo via herança.

Segue um exemplo de como fazer:
Condômino:

@Entity
@Table(name = "TB_CONDOMINO")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Condominio {
	
	@Id
	@Column(name = "ID_CONDOMINO")
	private Long id;
	
	// atributos e métodos do condômino
	
	// Uma prática que tenho quando trabalho com herança é criar métodos
	// para identificar melhor com qual especialização estou trabalhando
	// e obter o tipo adequado, assim:
	
	// Verifica se o condômino é um síndico
	public boolean isSindico() {
		return (this instanceof Sindico);
	}
	
	// Verifica se o condômino é um morador
	public boolean isMorador() {
		return (this instanceof Morador);
	}
	
	// Obtém o síndico através do condômino (se realmente for um síndico)
	public Sindico getAsSindico() {
		return (Sindico) this;
	}
	
	// Obtém o síndico através do condômino (se realmente for um morador)
	public Morador getAsMorador() {
		return (Morador) this;
	}
}

Síndico:

@Entity
@Table(name = "TB_SINDICO")
@PrimaryKeyJoinColumn(name = "ID_SINDICO")
public class Sindico extends Condomino {
	
	// atributos e métodos do síndico
	
}

Morador:

@Entity
@Table(name = "TB_MORADOR")
@PrimaryKeyJoinColumn(name = "ID_MORADOR")
public class Morador extends Condomino {
	
	// atributos e métodos do morador
	
}
N

Então simplifique.

Não é pq tem atributos em comum que vc é obrigado abstrair tudo em um classe e sair usando por aí.

Não tem nenhum problema em ter 3 ter classes ou mais onde o atributo nome, idade, data de nascimento sejam repeditos. Porém, se vc realmente se importar com isso, crie uma classe PessoaFisica(exemplo, ok, poderia ser DadosCadastrais) e mova os atributos em comuns para essa classe.

com isso teríamos algo como:

public class Sindico {
  private PessoaFisica pessoaFisica;
  private LocalDate fimdoMandato ;
}

Veja, temos várias soluções para o mesmo problema.

N

Exato, li errado.

Criado 11 de julho de 2016
Ultima resposta 11 de jul. de 2016
Respostas 7
Participantes 3