Delete - org.hibernate.exception.ConstraintViolationException

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 =]

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

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!

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, já 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

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

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 &quot;findByName( unidade.getNome() );&quot;
			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:

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