Hibernate com herança múltipla

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.

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.

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

[quote=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.[/quote]

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.

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.

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…

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?

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.

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:

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”.

[quote=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”.[/quote]

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