Hibernate com herança múltipla

10 respostas
felippesh

Olá,
Estou tendo certa dificuldade para entender como fazer para mapear o esquema do banco de dados abaixo. Nesse esquema tenho uma tabela person com campos de cadastro genéricos de pessoas físicas. Tem a tabela manager que no modelo de classes faz um extends de person. Idem para salesman. No banco, a modelagem foi fazer a chave primária de person, ser também a chave primária de manager e salesman, ao mesmo tempo que é chave extrangeira. A dúvida é, como proceder no hibernate para fazer o mapeamento usando annotations? Digo, a chave primária no caso é também extrangeira, então o hibernate tem que se ligar que o generate sequence vem de person, e aí gravar nas tabelas filhos… Alguém já teve que implementar algo parecido?
Valew.

10 Respostas

P

felippesh,

No modelo relacional, não existe o conceito de herança. Esqueça a tabela person e crie somente as tabelas manager e salesman, com todos os campos de cada um.

fabiofalci

Dá uma lida aqui
http://www.hibernate.org/hib_docs/v3/reference/en/html/inheritance.html

Paulo_Silveira

pango:
felippesh,

No modelo relacional, não existe o conceito de herança. Esqueça a tabela person e crie somente as tabelas manager e salesman, com todos os campos de cada um.

ou ainda, as tabelas manager e salesman possuem uma FK para a tabela person. senao vai ficar desnormalizado!

e o hibernate tem suporte a esse tipo de heranca, e no banco pode ficar como o pango ou eu falamos, depende do seu @InheritanceStrategy desejado.

Eu particularmente tive pessimas experiencias de performance do hibernate com heranca usando JOIN_TABLE.

felippesh

pango,

resolvi esse problema usando a estratégia “Tabela por subclasse” sugerida pelo hibernate. O banco continua o mesmo acima, e as anotações ficaram assim:

package org.ctm.value;

import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="person")
@Inheritance(strategy = InheritanceType.JOINED)
public class Person implements Serializable {
	public Person() {
	}
	
	@Id
	@SequenceGenerator(name="seqPerson", sequenceName="person_id_seq",  allocationSize=1)  
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seqPerson")  
        @Column(name="id")	
	private int id;
	
	@Column(name="name", nullable=true, length=255)	
	private String name;
	
	@Column(name="last_name", nullable=true, length=255)	
	private String last_name;
	
	@Column(name="middle_name", nullable=true, length=255)	
	private String middle_name;
	
	@Column(name="tax_id", nullable=true, length=255)	
	private String tax_id;
	
	@Column(name="personal_id", nullable=true, length=255)	
	private String personal_id;
	
	@Column(name="tax_business_id", nullable=true, length=255)	
	private String tax_business_id;
	
	@Column(name="create_date", nullable=true)	
	private java.sql.Timestamp create_date;
	
	@Column(name="update_date", nullable=true)	
	private java.sql.Timestamp update_date;
	
	@Column(name="description", nullable=true)	
	private String description;

	public void setId(int value) {
		this.id = value;
	}
	
	public int getId() {
		return id;
	}
	
	public int getORMID() {
		return getId();
	}
	
	public void setName(String value) {
		this.name = value;
	}
	
	public String getName() {
		return name;
	}
	
	// get's and set's dos outros atributos
	
}

… e na classe manager:

package org.ctm.value;

import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="manager")
@PrimaryKeyJoinColumn(name="person_id")
public class Manager extends Person implements Serializable {
	public Manager() {
	}
	
	@Column(name="login", nullable=false)	
	private String login;
		
	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}
	
}

para a classe salesman repetir a mesma idéia da classe manager

então, na superclasse colocar:
@Inheritance(strategy = InheritanceType.JOINED)

na classe especialista:
@PrimaryKeyJoinColumn(name=“person_id”)

com essa estratégia funcionou legal, quando vou persistir manager, não preciso inserir em person, pois o hibernate se liga, que os atributos herdados, tem que ser inseridos na tabela person, inclusive o id gerado pela sequence em person, é o id que é gravado na tabela manager.

valew.

P

felippesh,

Eu não disse que não era possível utilizar o esquema que você está usando. Você pode fazer como o Paulo Silveira sugeriu, mas eu realmente acho que fica um lixo em termos de clareza e performance.

Paulo Silveira ,

Concordo que o banco vai ficar desnormalizado, mas acho que é o tipo de situação onde normalização é um preciosismo técnico…

felippesh

pango,

discordo que o em termos de clareza vai ficar um lixo. essa estratégia dentre as que estudei, é a que mais se aproxima dos conceitos de OO. Quanto a performance, não sei dizer pois não fiz testes de carga até o momento. Se alguem já passou por problemas nesse sentido gostaria de ouvir sua opinião…

Paulo Silveira, que espécie de problemas de performance você considera neste caso?

Paulo_Silveira

Felipe, eu ja relatei minha experiencia aqui:

Segue o problema:

Quando voce tem muitas classes, fica SEM chance, ate mesmo pelo tamanho da sql gerada, que é ridiculamente grande.

Adolfo_Rodrigues

Dê uma lida no artigo aqui do GUJ mesmo, escrito pelo Maurício. Tem tudo bonitinho (modelo de classes, modelo entidade-relacional, classes, mapeamentos, etc)
http://www.guj.com.br/java.tutorial.artigo.174.1.guj
Ele usou a estratégia “table per subclass” pra mapear “pessoa”, “aluno” e “professor”. Pode ser que te ajude…

Editado:
O caso do artigo que te sugeri é o mesmo que você adotou (e que o Paulo já tinha indicado). Desconsidere a minha mensagem :slight_smile:

felippesh

Paulo, Adolfo e colegas
entendo as sugestões propostas, mas acho que me esqueci de comentar que na minha regra de negócio tenho a seguinte questõa: uma pessoa pode ser ao mesmo tempo “salesman” e “manager”. Então dessa forma, evito de replicar a informação na tabela salesman e manager. Quando fizer um update nessa pessoa, grava numa só tabela. Na minha perspectiva o modelo de negócio fica muito mais “limpo”.

P

felippesh:
Paulo, Adolfo e colegas
entendo as sugestões propostas, mas acho que me esqueci de comentar que na minha regra de negócio tenho a seguinte questõa: uma pessoa pode ser ao mesmo tempo “salesman” e “manager”. Então dessa forma, evito de replicar a informação na tabela salesman e manager. Quando fizer um update nessa pessoa, grava numa só tabela. Na minha perspectiva o modelo de negócio fica muito mais “limpo”.

Ahhhh tá…Então beleza, faz como o Paulo Sugeriu… :smiley:

Criado 12 de março de 2008
Ultima resposta 14 de mar. de 2008
Respostas 10
Participantes 5