Erro ao salvar filho de uma classe - resolvido

Analisando passo a passo pelo debug, o objeto arquivoImagem, está preenchido.

Mapeamento pai para filho:

@NotAudited
	@OneToMany(mappedBy = "contaPagarReceber", cascade = {CascadeType.PERSIST,
			CascadeType.MERGE, CascadeType.DETACH})
	public Set<ContaPagarReceberArquivoImagemEntity> getContasPagarReceberArquivosImagens() {
		return contasPagarReceberArquivosImagens;
	}

Preeenchimento

Set<ContaPagarReceberArquivoImagemEntity> cprai = new LinkedHashSet<>();
		for (ContaPagarReceberArquivoImagemEntity arqImg : entidade.getContasPagarReceberArquivosImagens()) {
			aplicacaoAuditoria(arqImg);
			if(entidadeGravar instanceof ContaPagarEntity){
				arqImg.setContaPagarReceber((ContaPagarEntity) entidadeGravar);
			} else {
				arqImg.setContaPagarReceber((ContaReceberEntity) entidadeGravar);
			}
			arqImg.setArquivoImagem(arqImg.getArquivoImagem());
			cprai.add(arqImg);
		}
		entidadeGravar.setContasPagarReceberArquivosImagens(cprai);

Método genérico de persist

private void persist(Object objeto) throws Exception {
		EntityManager em = JPAUtility.getEntityManager();
		try {
			EntityTransaction et = em.getTransaction();
			try {
				((Session) em.getDelegate()).setDefaultReadOnly(false);
				et.begin();
				em.detach(objeto);
				em.persist(objeto);
				em.flush();
				et.commit();
			} catch (PersistenceException e) {
				trataErrosDePersistenciaAntes(em, e);
				et.rollback();
			} catch (Exception e) {
				et.rollback();
				throw new RuntimeExceptionDao(e);
			} finally {
				((Session) em.getDelegate()).setDefaultReadOnly(true);
			}
		} finally {
			em.close();
		}
	}

Erro:

08:26:42,119 WARN  [org.hibernate.action.internal.UnresolvedEntityInsertActions] (default task-16) HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
	Unsaved transient entity: ([br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity#<null>])
	Dependent entities: ([[br.eti.netsoft.erp.modelo.financeiro.ContaPagarReceberArquivoImagemEntity#511c085f-165f-4438-a3ce-e4fe1a1d3c05]])
	Non-nullable association(s): ([br.eti.netsoft.erp.modelo.financeiro.ContaPagarReceberArquivoImagemEntity.arquivoImagem])
08:26:42,119 WARN  [org.hibernate.action.internal.UnresolvedEntityInsertActions] (default task-16) HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
	Unsaved transient entity: ([br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity#<null>])
	Dependent entities: ([[br.eti.netsoft.erp.modelo.financeiro.ContaPagarReceberArquivoImagemEntity#151decc8-73cb-4b8b-a278-35c2bfd08902]])
	Non-nullable association(s): ([br.eti.netsoft.erp.modelo.financeiro.ContaPagarReceberArquivoImagemEntity.arquivoImagem])
08:26:42,120 ERROR [br.eti.netsoft.dao.GHDAO] (default task-16) Erro  ao gravar objeto: br.eti.netsoft.dao.exception.RuntimeExceptionDao: java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : br.eti.netsoft.erp.modelo.financeiro.ContaPagarReceberArquivoImagemEntity.arquivoImagem -> br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity

O que pode ser este erro ?

Como é a estratégia de obter id da classe ArquivoImagemEntity?

Gerado automaticamente pelo banco de dados, um GUID

Pelo erro, você deve está tentando salvar um valor valor inválido em uma coluna not null (provavelmente um valor nulo).

Nesta classe: ContaPagarReceberArquivoImagemEntity ?

Não, o erro se refere ao fato de:

  • Ele estár inserindo um objeto em que ao menos um atributo é um objeto e esse objeto ainda não foi persistido
  • Ele estar atualizando um objeto que tenha uma lista e ao menos um elemento desta lista é novo.
  • Ele estar adicionando um objeto que tenha uma lista e esta lista possui elementos não salvos.

Ou seja. ele precisa salvar todos os atributos do objeto ou, no caso de coleção, os elementos da coleção.
Provavelmente, o mapeamento que ele está usando não contém a propriedade CASCADE.

O pior eh que tem um cascade. Bom, talvez esteja configurado errado.

Parece que o erro se refere a outro atributo da classe em questão.

Como teste, coloque um Cascade.ALL, pra ver o que acontece. =)

Estou inserindo um objeto que tem uma lista de outros objetos, com , cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH})

Vou testar

Vou analisar e vejo se a algum campo que está null

Com apenas estes trechos do código fica difícil ter uma visão maior.
Ainda mais que o erro se refere a um atributo cujo getter deveria ser

getArquivoImagem()

O que é diferente do que você apresentou aí, não é mesmo?

Isto é uma lista de imagens para uma contas

Cara, posta a classe ContaPagarReceberArquivoImagemEntity completa

package br.eti.netsoft.erp.modelo.financeiro;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;

import br.eti.netsoft.erp.modelo.ErpEntity;
import br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity;
import br.eti.netsoft.modelo.auditoria.AuditableBaseEntity;
import br.eti.netsoft.util.anotacao.ExclusaoLogica;

/**
 * @description Modelo para arquivos ou imagems para a contas pagar ou receber
 * @author GH SISTEMAS
 */
@Entity
@Table(name = "TB_CON_PAG_REC_IMG_ARQ", schema = "FINANCEIROS", indexes = {
		@Index(columnList = "ST_REGISTRO", name = "I1_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_CONTA_PAGAR_RECEBER", name = "I2_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_ARQUIVO_IMAGEM", name = "I3_CON_PAG_REC_IMG_ARQ")})
@Audited
@AuditOverride(forClass = AuditableBaseEntity.class)
@ExclusaoLogica
public class ContaPagarReceberArquivoImagemEntity extends ErpEntity {

	private static final long serialVersionUID = -7273641592040911533L;

	private ContaPagarReceberEntity contaPagarReceber;
	private ArquivoImagemEntity arquivoImagem;

	@Id
	@Override
	@Column(name = "PK_CON_PAG_REC_IMG_ARQ")
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid2")
	public String getId() {
		return super.getId();
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ContaPagarReceberEntity.class)
	@JoinColumn(name = "FK_CONTA_PAGAR_RECEBER", nullable = false)
	public ContaPagarReceberEntity getContaPagarReceber() {
		return contaPagarReceber;
	}

	public void setContaPagarReceber(ContaPagarReceberEntity contaPagarReceber) {
		this.contaPagarReceber = contaPagarReceber;
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ArquivoImagemEntity.class)
	@JoinColumn(name = "FK_ARQUIVO_IMAGEM", nullable = false)
	public ArquivoImagemEntity getArquivoImagem() {
		return arquivoImagem;
	}

	public void setArquivoImagem(ArquivoImagemEntity arquivoImagem) {
		this.arquivoImagem = arquivoImagem;
	}
}
package br.eti.netsoft.erp.modelo.financeiro;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;

import br.eti.netsoft.erp.modelo.ErpEntity;
import br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity;
import br.eti.netsoft.modelo.auditoria.AuditableBaseEntity;
import br.eti.netsoft.util.anotacao.ExclusaoLogica;

/**
 * @description Modelo para arquivos ou imagems para a contas pagar ou receber
 * @author GH SISTEMAS
 */
@Entity
@Table(name = "TB_CON_PAG_REC_IMG_ARQ", schema = "FINANCEIROS", indexes = {
		@Index(columnList = "ST_REGISTRO", name = "I1_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_CONTA_PAGAR_RECEBER", name = "I2_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_ARQUIVO_IMAGEM", name = "I3_CON_PAG_REC_IMG_ARQ")})
@Audited
@AuditOverride(forClass = AuditableBaseEntity.class)
@ExclusaoLogica
public class ContaPagarReceberArquivoImagemEntity extends ErpEntity {

	private static final long serialVersionUID = -7273641592040911533L;

	private ContaPagarReceberEntity contaPagarReceber;
	private ArquivoImagemEntity arquivoImagem;

	@Id
	@Override
	@Column(name = "PK_CON_PAG_REC_IMG_ARQ")
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid2")
	public String getId() {
		return super.getId();
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ContaPagarReceberEntity.class)
	@JoinColumn(name = "FK_CONTA_PAGAR_RECEBER", nullable = false)
	public ContaPagarReceberEntity getContaPagarReceber() {
		return contaPagarReceber;
	}

	public void setContaPagarReceber(ContaPagarReceberEntity contaPagarReceber) {
		this.contaPagarReceber = contaPagarReceber;
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ArquivoImagemEntity.class)
	@JoinColumn(name = "FK_ARQUIVO_IMAGEM", nullable = false)
	public ArquivoImagemEntity getArquivoImagem() {
		return arquivoImagem;
	}

	public void setArquivoImagem(ArquivoImagemEntity arquivoImagem) {
		this.arquivoImagem = arquivoImagem;
	}
}
package br.eti.netsoft.erp.modelo.financeiro;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.AuditOverride;
import org.hibernate.envers.Audited;
import org.hibernate.envers.RelationTargetAuditMode;

import br.eti.netsoft.erp.modelo.ErpEntity;
import br.eti.netsoft.erp.modelo.arquivoimagem.ArquivoImagemEntity;
import br.eti.netsoft.modelo.auditoria.AuditableBaseEntity;
import br.eti.netsoft.util.anotacao.ExclusaoLogica;

/**
 * @description Modelo para arquivos ou imagems para a contas pagar ou receber
 * @author GH SISTEMAS
 */
@Entity
@Table(name = "TB_CON_PAG_REC_IMG_ARQ", schema = "FINANCEIROS", indexes = {
		@Index(columnList = "ST_REGISTRO", name = "I1_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_CONTA_PAGAR_RECEBER", name = "I2_CON_PAG_REC_IMG_ARQ"),
		@Index(columnList = "FK_ARQUIVO_IMAGEM", name = "I3_CON_PAG_REC_IMG_ARQ")})
@Audited
@AuditOverride(forClass = AuditableBaseEntity.class)
@ExclusaoLogica
public class ContaPagarReceberArquivoImagemEntity extends ErpEntity {

	private static final long serialVersionUID = -7273641592040911533L;

	private ContaPagarReceberEntity contaPagarReceber;
	private ArquivoImagemEntity arquivoImagem;

	@Id
	@Override
	@Column(name = "PK_CON_PAG_REC_IMG_ARQ")
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid2")
	public String getId() {
		return super.getId();
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ContaPagarReceberEntity.class)
	@JoinColumn(name = "FK_CONTA_PAGAR_RECEBER", nullable = false)
	public ContaPagarReceberEntity getContaPagarReceber() {
		return contaPagarReceber;
	}

	public void setContaPagarReceber(ContaPagarReceberEntity contaPagarReceber) {
		this.contaPagarReceber = contaPagarReceber;
	}

	@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
	@ManyToOne(targetEntity = ArquivoImagemEntity.class)
	@JoinColumn(name = "FK_ARQUIVO_IMAGEM", nullable = false)
	public ArquivoImagemEntity getArquivoImagem() {
		return arquivoImagem;
	}

	public void setArquivoImagem(ArquivoImagemEntity arquivoImagem) {
		this.arquivoImagem = arquivoImagem;
	}
}

Aqui você não tem o cascade.

P.S.: Não gosto de usar anotações nos getters, fico perdido vendo esse código amontoado.

2 curtidas

É mesmo. Acho que o problema é este, correto ?

Vou testar e informo aqui.