Org.hibernate.TransientObjectException

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

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. [=

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.

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.

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

Tenho uma classe de processo

[code]@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;
}

}[/code]

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.

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

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

[code]@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("");
}[/code]

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

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

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:

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