Delete - org.hibernate.exception.ConstraintViolationException

6 respostas
C

Olá pessoal,

Estou tentando executar um delete de uma unidade que está relacionada a um perfil da seguinte maneira:

@Entity
@Table(name = "perfil")
public class Perfil {
	
	@Id
	@Column(name = "perfil_id")
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	
	@NotNull
	private String nome;
	
	@ManyToOne
	@JoinColumn(name="unidade_id")
	@NotNull
	private Unidade unidade;

	//..
}
@Entity
@Table(name = "unidade")
public class Unidade {

	@Id
	@Column(name = "unidade_id")
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
	
	private String nome;
	private String descricao;

	//...
}

Método delete:

//Delete
	public boolean delete(Unidade unidade) {
		try {
			entityManager.remove(unidade);
			return true;
			
		} catch (Exception ex) {
			getFacesContext().addMessage(null,new FacesMessage(ex.getMessage()));
			UnidadeDAO.log.error(ex);
			return false;
		}
		
	}

	protected FacesContext getFacesContext() {
		return FacesContext.getCurrentInstance();
	}

Mas ao tentar executá-lo ocorre o seguinte erro:

2007-10-29 16:54:43,218 ERROR hibernate.util.JDBCExceptionReporter  -> Cannot delete or update a parent row: a foreign key constraint fails (`exemplo/perfil`, CONSTRAINT `FKC4E369CC301860CE` FOREIGN KEY (`unidade_id`) REFERENCES `unidade` (`unidade_id`))
2007-10-29 16:54:43,218 ERROR event.def.AbstractFlushingEventListener  -> Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)

Como posso tratar isto? Pois ao executar o meu método delete, ele não passa no catch…
Alguém pode me dar uma dica?

Obrigada =]

6 Respostas

T

Olá, .cris!!! Tudo bem?!

O problema pode estar relacionado aos estados persistentes do hibernate e/ou da JPA.

Você está tentando remover um objeto detached com o id preenchido.

Para solucionar o problema, você precisa mandar remover a instância que é managed.

Faça o sequinte:

public void remove(Unidade unidade) {
   this.daoFactory.beginTransaction();
   UnidadeDao dao = this.daoFactory.getUnidadeDao();

   Unidade managed = dao.load(unidade.getId());

   dao.remove(managed);
   this.daoFactory.commit();
 }

Espero ter te ajudado!!!

[ ]

Tubarão

C

Olá Tubarao! Tudo bem sim!

Certo, no caso eu tenho que passar o objeto detached para o estado persistente.
Tentei fazer isso por meiodo método merge do entityManager, mas não mudou nada, o mesmo erro continua. :cry:

Você sabe o que eu posso estar fazendo de errado? :?

Não tem como eu recuperar este erro para tratá-lo? Pois gostaria de exibir uma tela dizendo que não foi possivel excluir a unidade, já que ela está associada a um perfil.

Obrigada pela ajuda!

T

Olá .cris!!

Estou te mandando o meu delete para vc dar uma olhada:

/**
	 * Remove o objeto da session.
	 * @param obj Objeto passado como parâmetro, que extenda T.
	 */
	public void remove (T obj) {
		logger.debug("removing" + obj + " " + this.clazz);
		/**
		 * Carrega um novo objeto para não ter problema,  existe um outro objeto 
		 * managed com o mesmo id na Session,
		 */
		T objetoManaged = this.procura((Long) this.getId(obj, this.clazz));
		this.session.delete(objetoManaged);
	}

Método procura:

/** * Busca um objeto pelo id passado como parâmetro. * @param id Long. * @return T Objeto. * @throws org.hibernate.HibernateException */ @SuppressWarnings("unchecked") public T procura(Long id) throws org.hibernate.HibernateException{ logger.debug("searching " + this.clazz.getName() + " for " + id); return (T) session.load(this.clazz, id); }

Método getId:

/** * Buscar o campo 'id' do objeto passado como argumento. * @param val Objeto. * @param classe * @return Id. */ private Object getId(Object val, Class<? extends Object> classe) { try { return classe.getMethod("getId").invoke(val); } catch (IllegalArgumentException e) { logger.error("Erro ao invocar id - IllegalArgumentException: ", e); } catch (SecurityException e) { logger.error("Erro ao invocar id - SecurityException: ", e); } catch (IllegalAccessException e) { logger.error("Erro ao invocar id - IllegalAccessException: ", e); } catch (InvocationTargetException e) { logger.error("Erro ao invocar id - InvocationTargetException: ", e); } catch (NoSuchMethodException e) { logger.error("Erro ao invocar id - NoSuchMethodException: ", e); } return null; }

Em relação a mensagem de erro que você vai exibir, trate isso na sua lógica!

Qualquer dúvida post aqui novamente!

Um abraço

Tubarão

C

Olá Tubarao!

Muito obrigada pelo exemplo de delete que você me enviou!

Bom, o erro persiste… :cry:
Quando eu tento remover uma unidade que não está relacionada a nenhum perfil, ele consegue efetuar o delete normalmente :slight_smile: , já quando eu tento deleter uma que está associada a um perfil, ele dá a ConstraintViolationException, está certo, eu sei que uma violação de chave está sendo feita, mas eu gostaria de saber como pegá-la e tratá-la para poder exibir uma mensagem, e não aparecer aquela tela de erro Apache/ Tomcat… :?

Porque o que acontece é o seguinte: quando ocorre a violação, ele passa pele delete, entra no try e não sai…

public boolean delete(Unidade unidade) {
		try {
			entityManager.remove(unidade);
			return true;   // Ele acaba passando aqui! 
			
		} catch (Exception ex) {
			getFacesContext().addMessage(null,new FacesMessage(ex.getMessage()));
			UnidadeDAO.log.error(ex);
			return false;
		}
		
	}

Ele não deveria entrar no catch? Como faço para isso acontecer?

Muito obrigada pela ajuda!

[]'s

K

Antes de remover a Unidade de um "load" nela, neste codigo voce nao esta fazendo isso
faltou uma linha ai fazendo um findById(Integer id);

public boolean delete(Unidade unidade) {
		try {
                        unidade = unidadeDAO.findById( unidade.getId() ); //caso nao tenha o id use um "findByName( unidade.getNome() );"
			entityManager.remove( unidade );
			return true;   // Ele acaba passando aqui! 
		} catch (Exception ex) {
			getFacesContext().addMessage(null,new FacesMessage(ex.getMessage()));
			UnidadeDAO.log.error(ex);
			return false;
		}
		
	}

Uma exceção como o proprio nome diz é uma "excessao a regra" algo fora do comun aconteceu.
Tens que pesquisar a unidade e com alguma regra você conferir se pode excluir ela ou não.

Não conheco a modelagem mas supondo um caso simples, você nao pode excluir uma unidade
caso tenha Usuarios vinculados a ela. Entao antes de remover a unidade você deve fazer um "load"
na unidade e conferir se a List<Usuario> esta vazia… pegou a ideia ?

1. 2007-10-29 16:54:43,218 ERROR hibernate.util.JDBCExceptionReporter  -&gt; Cannot delete or update a parent row: a foreign key constraint fails (`exemplo/perfil`, CONSTRAINT `FKC4E369CC301860CE` FOREIGN KEY (`unidade_id`) REFERENCES `unidade` (`unidade_id`))  
   2. 2007-10-29 16:54:43,218 ERROR event.def.AbstractFlushingEventListener  -&gt; Could not synchronize database state with session  
   3. org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update  
   4.     at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)

E os cascades como estao ? :roll:

Boa sorte! :smiley:

T

Olá .cris!!

Desculpe, eu não tinha entendido direito a sua dúvida, mas o nosso amigo keller respondeu tudo!!!

Qualquer coisa post aqui sua dúvida!!!

Um abraço,

Tubarão

Criado 29 de outubro de 2007
Ultima resposta 30 de out. de 2007
Respostas 6
Participantes 3