Hibernate Autoincrement em uma relação 1:1

9 respostas
J

Primeiramente, olá a todos!

Quero informar àqueles que de alguma forma ajudaram ou tentaram me ajudar com a Saga: Netbeans + JSP + Struts + Hibernate chegou ao fim da sua primeira parte.

Agora vamos às dúvidas adolescentes… ou de gente grande!

Tenho três tabelas que mantêm uma relação 1:1, sendo Pessoa, PJ e PF, em que um PJ tem associado uma Pessoa e PF tem associado a ele uma Pessoa também. Seria como se a classe pessoa fosse abstrata mas não é e DEVE ser persistida. A questão é que faço a persistência de um objeto Pessoa somente quando é cadastrada um PJ ou um PF. O problema: preciso do ID (que é autoincrement) de Pessoa que foi persistido para poder persistir tanto PJ quanto PF. Alguém tem alguma solução, como por exemplo: recuperar através do Hibernate o ID de um objeto que acabou de ser persistido?

[]'s, JWCunha

9 Respostas

A

Amigo, aqui na empresa o banco é identico ao seu.
Entao veja seu soluciona seu problema.
Tenho uma tabela Pessoa e PessoaFisica.

[ Pessoa ]   <Table>
 cod_pessoa <Column>  <PK> 
 nome          <Column>
 
 ---------------------------
 
 [ PessoaFisica ]   <Table>
 cod_pessoa        <Column>  <PK>  <FK -> cod_pessoa [ Pessoa ] >
 cpf                     <Column>
@Entity
 @Table
 @Inheritance(strategy = InheritanceType.JOINED)
 public class  Pessoa {
 
 	// Fields
 	private int codpessoa;
 	private String nome;
 
 	// Property accessors
 	@Id @GeneratedValue
 	@Column(name = "PESSOA", unique = true, nullable = false, insertable = true, updatable = true)
 	public int getCodpessoa() {
 		return this.codpessoa;
 	}
 
 	public void setCodpessoa(int codpessoa) {
 		this.codpessoa = codpessoa;
 	}
 
 	@Column(name = "NOME", unique = false, nullable = true, insertable = true, updatable = true)
 	public String getNome() {
 		return this.nome;
 	}
 
 	public void setNome(String nome) {
 		this.nome = nome;
 	}
 
 }

----|----

@Entity
 @Table(name = "pessoa_fisica")
 public class PessoaFisica extends Pessoa {
 
 	// Fields 
 	private String rg;	
 
 	// Property accessors
 	@Column(name = "RG", unique = false, nullable = true, insertable = true, updatable = true, length = 15)
 	public String getRg() {
 		return this.rg;
 	}
 
 	public void setRg(String rg) {
 		this.rg = rg;
 	}
 
 
 }

OBS: Coloquei somente PF pois a juridica é so modificar a PF.
E Simplifiquei...

[]'s

zetamayossi

Cara, num sei bem se entendi o problema não mas vamos lá…

No seu sistema vc tem a possibilidade de cadastrar uma pessoa, sem vinculo com PJ ou PF?! Pra que?!

Caso nao precise, pq vc nao muda um pouco a arquitetura dessas tabelas?

Com o hibernate vc pode colocar tipagem de objetos que ele entende qual objeto vc esta sendo persistido, através de herança. Dai vc precisaria apenas de uma tabela no banco

No caso eu faria uma herança ai, onde PF e PJ herdariam de PESSOA.
A tabela chamaria PESSOA mesmo mas com um campo chamado TIPO (que definiria se PJ ou PF).

Dai no mapeamento deve haver algumas modificações.

Primeiramente acrescentar um discriminator ao mapeamento do objeto PESSOA (que é o que será persistido) para o campo TIPO (que é o que diferenciará os subtipos PF e PJ).

<discriminator 
    	 column="TIPO"
    	 type="string"
    />

Feito isso, agora vc deve definir os subtipos de pessoas que existem, no mapeamento do objeto PESSOA tbm.

<subclass
    	name="PF"
    	discriminator-value="F"
    />
    
    <subclass
    	name="PJ"
    	discriminator-value="J"
    />

Onde PF e PJ são objetos da aplicação herdados de PESSOA.

Dai acabou, é só salvar os PF e os PJ que o discriminator da conta do recado. Como estao definidos os subtipos, ele sabe qual TIPO cada classe é, devido a herança. Logo o campo TIPO seria setado de acordo com o objeto persistido (F para PF ou J para PJ). É bom lembrar que esse atributo TIPO nao deve ser manipulado pois pode gerar erros. Eu setaria ele no construtor de cada objeto, setando ‘F’ no construtor de PF e ‘J’ para PJ. Feito isso acabou. Use como se fosse uma pessoa mesmo.

Na busca funciona da mesma forma mas no inverso. Atraves do discriminator, o hibernate molda os objetos atraves do campo TIPO. Dai se estiver com valor F, virá um objeto PF, caso J virá um objeto PJ.

Lembrando que ambos são pessoas devido a herança.

Pro seu problema do ID ai, pelos teste que eu já realizei, só de vc comitar a transação, o hibernate já seta o ID do objeto. Dai vc nao precisa preocupar, a nao ser que gere alguma exception, claro.

Acho q ajudei.
Caso nao, fica ai uma solução.
Vlw

J

Adoria ajudar mas não consegui fazer nem mesmo o que vc me passou rodar!!!

J

Fiz da forma como foi dito na primeira sugestão e estou persistindo da seguinte forma, mas da erro do SGBD pois a chave pessoa_id em pf está nula… :frowning:

private void createAndStore(HttpServletRequest request) {
try{

Pf pf   = new Pf();       
        
        Session session = HibernateUtil.getSessionFactory().openSession();
        
        pf.setNumcep(request.getParameter("numCep"));
        pf.setUf(request.getParameter("Uf"));
        pf.setCidade(request.getParameter("cidade"));
        pf.setBairro(request.getParameter("bairro"));
        pf.setLogradouro(request.getParameter("logradouro"));
        pf.setTipoLogradouro(request.getParameter("tipo_logradouro"));
        pf.setNumero(request.getParameter("numero"));
        pf.setComplemento(request.getParameter("complemento"));
        pf.setFone(request.getParameter("fone"));
        pf.setFax(request.getParameter("fax"));
        pf.setEmail(request.getParameter("email"));
        pf.setUrl(request.getParameter("url"));
        pf.setLogin(request.getParameter("login"));
        pf.setSenha(request.getParameter("password1"));      
        
        int permissao_id = Integer.parseInt(request.getParameter("permissao"));
        Query select = session.getNamedQuery("Permissao.findById");
        select.setInteger("id",permissao_id);    
        List permissao = select.list();                      
        pf.setPermissaoId(((Permissao)(permissao.get(0))));  
       
        
        pf.setCpf(request.getParameter("cpf"));
        pf.setEmail(request.getParameter("email"));
        pf.setNome(request.getParameter("nome"));
        pf.setFotoPath(request.getParameter("foto_path"));      
        pf.setPessoaId(pf.getId());
        
        Transaction tx = session.beginTransaction();                     
        tx = session.beginTransaction();
        session.save(pf);
        tx.commit();
        
        session.close();
    }catch(HibernateException e){
        e.printStackTrace();
    }
}

O que está errado?

zetamayossi

Ai cara… num sei se vai te ajudar ou complicar mais…

Mas eu to vendo ai que quem tá controlando as transações tá sendo vc mesmo… no código…

Já ouviu falar de JTA?! Java Transaction API?!

Então… quando vc configura uma JTA para a sua aplicação e dependendo de como configura… vc nao é mais o responsável por cuidar das transações… ou seja… vc não precisa ficar tratando roolbacks ou commits…

Vamos supor que vc utilize EJBs na sua aplicação… sempre q um ejb é criado e dentro dele aja alguma requisição de transação… uma sessão no hibernate é aberta… dai vc faz tudo q tem q fazer (vai jogando td na transação)… Um poko antes do ejb ser destruido… a JTA comita tudo que vc realizou na sessão aberta anteriormente… e, logo, destroi a sessão…

Mas acho q funciona para pequenas aplicações tbm… sem EJBs…

Dá uma procurada sobre o assunto… as vezes pode haver uma solução para este seu problema…

Especificação da Sun para JTA
http://java.sun.com/products/jta/

J

zetamayossi:
Ai cara… num sei se vai te ajudar ou complicar mais…

Mas eu to vendo ai que quem tá controlando as transações tá sendo vc mesmo… no código…

Já ouviu falar de JTA?! Java Transaction API?!

Então… quando vc configura uma JTA para a sua aplicação e dependendo de como configura… vc nao é mais o responsável por cuidar das transações… ou seja… vc não precisa ficar tratando roolbacks ou commits…

Vamos supor que vc utilize EJBs na sua aplicação… sempre q um ejb é criado e dentro dele aja alguma requisição de transação… uma sessão no hibernate é aberta… dai vc faz tudo q tem q fazer (vai jogando td na transação)… Um poko antes do ejb ser destruido… a JTA comita tudo que vc realizou na sessão aberta anteriormente… e, logo, destroi a sessão…

Mas acho q funciona para pequenas aplicações tbm… sem EJBs…

Dá uma procurada sobre o assunto… as vezes pode haver uma solução para este seu problema…

Especificação da Sun para JTA
http://java.sun.com/products/jta/

Amigo, valeu pelas dicas e interesse. O problema maior para mim ainda está no mapeamento, desde ontem não fui dormir porque não consigo inserir simultaneamente os dados de Pessoa e PessoaFisica (Pf) simultaneamente setando o pessoa_id FK de Pf como sendo o id de Pessoa que acabou se ser inserido. A sua seugestão na mensagem anterior de usar um identificador (F -> Pf e J -> Pj) é interessante mas daí eu teria que pagar o custo da desnormalização do meu banco de dados, o que não posso fazer. Valeu mesmo, mas se souber de alguém ou como faço a annotation para subclasse de tal forma que o Hibernate salve o id de pessoa em pessoa_id de Pf, faça a gentileza.

[]'s

J
afsrj:
Amigo, aqui na empresa o banco é identico ao seu. Entao veja seu soluciona seu problema. Tenho uma tabela Pessoa e PessoaFisica.
[ Pessoa ]   <Table>
 cod_pessoa <Column>  <PK> 
 nome          <Column>
 
 ---------------------------
 
 [ PessoaFisica ]   <Table>
 cod_pessoa        <Column>  <PK>  <FK -> cod_pessoa [ Pessoa ] >
 cpf                     <Column>
@Entity
 @Table
 @Inheritance(strategy = InheritanceType.JOINED)
 public class  Pessoa {
 
 	// Fields
 	private int codpessoa;
 	private String nome;
 
 	// Property accessors
 	@Id @GeneratedValue
 	@Column(name = "PESSOA", unique = true, nullable = false, insertable = true, updatable = true)
 	public int getCodpessoa() {
 		return this.codpessoa;
 	}
 
 	public void setCodpessoa(int codpessoa) {
 		this.codpessoa = codpessoa;
 	}
 
 	@Column(name = "NOME", unique = false, nullable = true, insertable = true, updatable = true)
 	public String getNome() {
 		return this.nome;
 	}
 
 	public void setNome(String nome) {
 		this.nome = nome;
 	}
 
 }

----|----

@Entity
 @Table(name = "pessoa_fisica")
 public class PessoaFisica extends Pessoa {
 
 	// Fields 
 	private String rg;	
 
 	// Property accessors
 	@Column(name = "RG", unique = false, nullable = true, insertable = true, updatable = true, length = 15)
 	public String getRg() {
 		return this.rg;
 	}
 
 	public void setRg(String rg) {
 		this.rg = rg;
 	}
 
 
 }

OBS: Coloquei somente PF pois a juridica é so modificar a PF.
E Simplifiquei...

[]'s

Amigo, manda pra mim como vc grava o objeto. Pq quando estou mandando gravar ele dá erro pois não consegue mapear meu atributo FK pessoa_id de Pf como sendo o atributo Pk id da sua classe-mãe Pessoa.

Vc seta o pessoa_id da classe Pf? como? e para gravar?

zetamayossi

E ai jwcunha… é, esse bug ai tá t arrebentando mesmo hein…??? :lol:

Aki oh… achei algumas anottations do Hibernate…

Procura por ‘Mapping inheritance’ no sumário…
Ou por ‘Table per class’

Lá tem a sugestão que te dei (das subclasses)… só q com annotations…

O link é http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e749

Vamos caba kese bug ai… na luta nois consegue…!! :stuck_out_tongue:

J

zetamayossi:
E ai jwcunha… é, esse bug ai tá t arrebentando mesmo hein…??? :lol:

Aki oh… achei algumas anottations do Hibernate…

Procura por ‘Mapping inheritance’ no sumário…
Ou por ‘Table per class’

Lá tem a sugestão que te dei (das subclasses)… só q com annotations…

O link é http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e749

Vamos caba kese bug ai… na luta nois consegue…!! :stuck_out_tongue:

No meu caso tem que ser o

Joined subclasses
. Estou com o livro Hibernate em Ação (Hibernate in Action) e este é o meu caso.

Criado 20 de dezembro de 2006
Ultima resposta 21 de dez. de 2006
Respostas 9
Participantes 3