Org.hibernate.TransientObjectException

9 respostas
K

Boa tarde pessoal, seguinte, eu estou tentando gravar em uma tabela, onde nela possui muito campos many-to-one, mas nem todos são obrigatorios.

Então da o erro

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.tga.juridico.entidades.cadastros.Acao
org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:243)

Correto, ele está passando uma referencia com atributos nullos,

mas pq o hibernate não set o atributo nulo, ja que os atributos desse atributo estão nulo.

Dai sou obrigato a tratar na classe

algo como

public void setAcao(Acao acao) { if (acao.getId() != null) this.acao = acao; else this.acao = null; }

Alguem teria uma luz para fazer algo mais genérico, para não ter refatorar minha aplicação.

Att.

Kiver

9 Respostas

H

Ele não reclamou de objeto null, ele reclamou que você está tentando salvar um relacionamento com um objeto que ainda não foi salvo.

Imagine soh

casa.setDono(pessoa);

pessoa.setCasa(casa);

Ao tentar salvar pessoa, se a casa não existir no banco ele vai reclamar que esse cara é transiente.

Ou você salva o objeto antes (no caso do exemplo acima) a casa, ou então você utiliza do Cascade que pode ser adicionado ao relacionamento. [=

K

Oi jake,

então, ai que, essa tela é uma master detail, onde ja passo pelo formulario a informação.

quando a informação é passada, ou seja o id, grava tranquilo,
mas quando o usuario não preenche, o que não é obrigação, ele retorna um objeto, com todas as propriedades nulas.

Ta ai. será isso um problema do vraptor ( nada haver com o tópico ) ou do hibernate.

H

Veja como os dados estão chegando. Pode ter algum objeto chegando sem o ID. se o objeto existir mas o ID estiver como 0, o JPA/Hibernate considera como um objeto novo.

K

Não sei se fui bem claro, vou tentar da seguinte maneira

Tenho uma classe de processo

@Entity
public class Processo implements IBean{
  
	@ManyToOne
	private Acao acao;

	public Acao getAcao() {
			return acao;
	}

	public void setAcao(Acao acao) {
		if (acao.getId() != null)
			this.acao = acao;
		else
			this.acao = null;
	}
}

quando vou salvar, eu recebo o Bean no meu controller

@Post
	@Path("/processo")
	public void adiciona(final Processo processo) {
		dao.salva(processo);
		result.redirectTo(this).lista("");
	}

nesse bean, ja tenho todos os atributos preenchidos.

onde no caso o usuario não preencheu acao.

retornando um objeto acao mas com propriedades nulas

o por isso de eu ter que usar isso

public void setAcao(Acao acao) {
		if (acao.getId() != null)
			this.acao = acao;
		else
			this.acao = null;
	}

Só que é uma medida ruim para mim, pois possuo muitos relacionamentos.

Não sei se ficou claro.

I

Não entendi muito bem o que vc falou, mas veja que no seu código vc seta o objeto como null caso o id seja null, logo, o objeto é considerado transient. Como o JAKE falou, ou acerta no cascade ou salva primeiro.

Espero ter ajudado.

Abçs

K

Da forma que eu coloquei antes não funciona. dai tive que mudar no controller para

@Post
	@Path("/processo")
	public void adiciona(final Processo processo) {
		if(processo.getAcao().getId() == null){
			processo.setAcao(null);
		}
		
		if(processo.getCamara().getId() == null){
			processo.setCamara(null);
		}
		
		if(processo.getComarca().getId() == null){
			processo.setComarca(null);
		}
		
		if(processo.getMoeda().getId() == null){
			processo.setMoeda(null);
		}
		
		if(processo.getInstancia().getId() == null){
			processo.setInstancia(null);
		}
		
		if(processo.getJustica().getId() == null){
			processo.setJustica(null);
		}
		
		if(processo.getTribunal().getId() == null){
			processo.setTribunal(null);
		}
		
		if(processo.getVara().getId() == null){
			processo.setVara(null);
		}
		
		if(processo.getSituacao().getId() == null){
			processo.setSituacao(null);
		}
		
		dao.salva(processo);
		result.redirectTo(this).lista("");
	}

Mas para mim essa é uma forma muito ruim de se lidar com esse problema. :(

H

Nesse caso você pode utilizar cascade em todos os relacionamentos. Caso você utilize CasacdeType.Persist, toda vez que você salvar um cara o JPA irá salvar o resto para você.

K

Olá jake, seguinte, tentei fazer oque vc flw, adicionei somente em Acao acao

e nada

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.tga.juridico.entidades.cadastros.Acao org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:243)

@ManyToOne (cascade=CascadeType.PERSIST) private Acao acao;

:frowning:

H

Vc tem que adicionar em todos os relacionamentos. E se você adicionou persist, essa ação funciona apenas na hora de salvar.

Criado 31 de maio de 2012
Ultima resposta 1 de jun. de 2012
Respostas 9
Participantes 3