[Resolvido] Violação de chave estrangeira ao deletar registro

Olá pessoal!
Tenho um atributo mapeado em @OneToOne:

@OneToOne(targetEntity=Foto.class)
	private Foto avatar;

Ao tentar remover a foto na tabela Foto sou impedido, já que a mesma ainda é referênciada na tabela Imovel, conforme a imagem:

Estou tentando resolver a questão com o seguinte código:

public void remove(Long idImovel, Long idFoto) {
		 Foto foto = fotoDAO.carrega(idFoto);
		 Imovel imovel = imovelDAO.carrega(idImovel);
		 			 
		 if(idFoto == imovel.getAvatar().getIdFoto()) { // criei esta condição pra deletar o avatar
			 imovel.setAvatar(null); //aqui seto a referência em null para poder excluir o registro da foto mais abaixo
			 imovelDAO.atualiza(imovel); // atualizo o imovel com avatar == null			 
		 }	   
		 imagens.remove(foto);	
		 fotoDAO.remove(foto);	
}	  

Mas continuo impedido mesmo setando em “null” a coluna avatar, alguém sabe como posso resolver isso? Ou talvez com alguma anotação ou parâmetro diretamente na classe?
Abraço!

[quote=Guevara]Olá pessoal!
Tenho um atributo mapeado em @OneToOne:

@OneToOne(targetEntity=Foto.class)
	private Foto avatar;

Ao tentar remover a foto na tabela Foto sou impedido, já que a mesma ainda é referênciada na tabela Imovel, conforme a imagem:

Estou tentando resolver a questão com o seguinte código:

public void remove(Long idImovel, Long idFoto) {
		 Foto foto = fotoDAO.carrega(idFoto);
		 Imovel imovel = imovelDAO.carrega(idImovel);
		 			 
		 if(idFoto == imovel.getAvatar().getIdFoto()) { // criei esta condição pra deletar o avatar
			 imovel.setAvatar(null); //aqui seto a referência em null para poder excluir o registro da foto mais abaixo
			 imovelDAO.atualiza(imovel); // atualizo o imovel com avatar == null			 
		 }	   
		 imagens.remove(foto);	
		 fotoDAO.remove(foto);	
}	  

Mas continuo impedido mesmo setando em “null” a coluna avatar, alguém sabe como posso resolver isso? Ou talvez com alguma anotação ou parâmetro diretamente na classe?
Abraço!
[/quote]
Rapaz eu costumo resolver esse tipo de problema adicionando uma coluna ao dado chamada ativo do tipo boolean, aí em vez de excluir esses campos com referência eu opto por marcar ele como ativo = false :idea:

Bom dia…

A solução do Carlos é viável!

Mas caso queira excluir efetivamente seu registro, opte por exclusão em cascata.

OneToOne(targetEntity=Foto.class)  
@Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Foto avatar; 

E faça a chamada somente para o objeto Imovel, e o hibernate irá excluir o depentende. :wink:

  ImovelDAO.remove(imovel);    

Abrs

1 curtida

Opa! Obrigado pela dicas pessoal, mas o problema não é remover imovel e em cascata a foto.
O lance é que tenho uma galeria de fotos, consigo remover todas menos a que está referenciada na tabela imovel, ou seja, preciso deletar a foto avatar sem deletar o imovel em cascata, eu tinha tentado uma anotação aqui e aconteceu isso, deletei a foto avatar e o imóvel foi pro espaço. Preciso remover a foto sem remover o imovel, setando a coluna avatar em null.
A dica de adicionar campo boolean eu tinha feito antes, mas fica inviável, pois preciso da id da foto que é avatar para poder carreá-la junto com o imóvel.
Tõ pesquisando aqui o que posso fazer a respeito, se tiverem outra idéia é só falar.
Valeu!!!

[quote=Guevara]Opa! Obrigado pela dicas pessoal, mas o problema não é remover imovel e em cascata a foto.
O lance é que tenho uma galeria de fotos, consigo remover todas menos a que está referenciada na tabela imovel, ou seja, preciso deletar a foto avatar sem deletar o imovel em cascata, eu tinha tentado uma anotação aqui e aconteceu isso, deletei a foto avatar e o imóvel foi pro espaço. Preciso remover a foto sem remover o imovel, setando a coluna avatar em null.
A dica de adicionar campo boolean eu tinha feito antes, mas fica inviável, pois preciso da id da foto que é avatar para poder carreá-la junto com o imóvel.
Tõ pesquisando aqui o que posso fazer a respeito, se tiverem outra idéia é só falar.
Valeu!!![/quote]

Mostre como está o relacionamento de imagens para foto…

Talvez seja necessário vc atualizar o objeto imagens tb…

Na classe Imovel tenho isto:

@OneToMany(targetEntity=Foto.class, mappedBy = "imovel",orphanRemoval=true)	
	public List<Foto> fotos; 

@OneToOne(targetEntity=Foto.class)
	private Foto avatar;

// gets e sets

E na classe Foto está assim:

@ManyToOne
	private Imovel imovel;	
// gets e sets

O problema está sendo em remover a foto que é avatar, pq na tabela Imovel existe uma coluna imovel.avatar.idFoto,ou seja, é remover o registro de foto e atualizar essa coluna pra null, mas sem deletar o imóvel.
Abraço!

Você tentou dar um merge na sua entidade Imovel e Imagens?

imovel.setAvatar(null);
imagens.remove(foto); 
dao.merge(imovel);
dao.delete(foto);

Remova e de um anule o objeto, depois da um merge em imovel…

Já tentei dar um “merge”, mas não adiantou. Ainda tô pesquisando o pq disso, já que aparentemente dar um set null em avatar deveria funcionar. =/

Este trecho de código está errado, vc deveria remover da lista antes de fazer o merge…

      Foto foto = fotoDAO.carrega(idFoto);  
          Imovel imovel = imovelDAO.carrega(idImovel);  
                        
          if(idFoto == imovel.getAvatar().getIdFoto()) { // criei esta condição pra deletar o avatar  
              imovel.setAvatar(null); //aqui seto a referência em null para poder excluir o registro da foto mais abaixo  
              imovelDAO.atualiza(imovel); // atualizo o imovel com avatar == null               
          }       
          imagens.remove(foto);    
          fotoDAO.remove(foto)

Ficaria assim

          if(idFoto == imovel.getAvatar().getIdFoto()) { // criei esta condição pra deletar o avatar  
              imovel.setAvatar(null); //aqui seto a referência em null para poder excluir o registro da foto mais abaixo  
			  imovel.getImagens().remove(foto);    
              imovelDAO.atualiza(imovel); // atualizo o imovel com avatar == null               
          }       
          fotoDAO.remove(foto)

Caso tenha tentado assim, poste a exception para vermos o que ocorre…

A minha classe Imagens é para armazenar e deletar as imagens da pasta, a classe Foto é onde salvo os dados da foto no banco, nome, id, url. O pior é que a condição if() é verdadeira:
url: http://localhost:8080/imobiliaria/foto/remove/83/264
Onde 83 é a id do imovel e 264 é a id da foto.

public void remove(Long idImovel, Long idFoto) {
		 Foto foto = fotoDAO.carrega(idFoto);
		 Imovel imovel = imovelDAO.carrega(idImovel);
		 	
		 if(idFoto == imovel.getAvatar().getIdFoto()) { // condição verdadeira 264 é igual a 264
			 Foto avatar = null; // inicializo avatar com null
			 imovel.setAvatar(avatar); // seto avatar com null
			 imovelDAO.atualiza(imovel); // atualizo o imovel com o avatar ja zerado, teoricamente já posso deletar o registro da foto na tabela Foto
		 }		 
		 imagens.remove(foto); // removo a foto da pasta
		 fotoDAO.remove(foto); // aqui dá o pau, o avatar não foi zerado lá no if()		  

Stacktrace:

root cause

java.sql.BatchUpdateException: Entrada em lote 0 delete from Foto where id_foto='264' foi abortada. Chame getNextException para ver a causa.
	org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2569)
	org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1796)
	org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:407)
	org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2708)
	org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
	org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
	org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
	org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
	org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
	org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
	org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
	org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
	org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
	br.com.imobiliaria.dao.FotoDAO.remove(FotoDAO.java:38)
	br.com.imobiliaria.controller.FotoController.remove(FotoController.java:111)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	java.lang.reflect.Method.invoke(Method.java:597)

Não entendi o pq não está zerando a coluna avatar na tabela Imovel, já dei um clean no tomcat e tb não surtiu efeito.

Descobri pessoal, só podia ser isto mesmo:

 if(idFoto.equals(imovel.getAvatar().getIdFoto())) 

É pra usar equals() e não “==”.
Valeu pela força!

[quote=Guevara]Descobri pessoal, só podia ser isto mesmo:

 if(idFoto.equals(imovel.getAvatar().getIdFoto())) 

É pra usar equals() e não “==”.
Valeu pela força![/quote]

kkkkkkkkkk, e eu pensando que era mapeamento.
já iria sugerir para vc usar um update em hql e depois dar uma pesquisada neste erro rsrs

abraço

coloca como [Resolvido]

hehehe, quebrando a cabeça a gente aprende, tinha esquecido do equals(), de repente deu aquele estalo no cérebro, foi tiro e queda.
Já alterei o tópico como [Resolvido].
Abraço!!

Poxa, eu gostaria de fazer exatamente o OPOSTO do tópico,

possuo uma tablea UNCIONARIO que possui uma chave estrangeira para USUARIO, gostaria de deletar o USUARIO ao mandar excluir o ogbeto do tipo USUARIO que mando ao

FuncionarioDAO.excluir();

no meu caso o funcionario é excluido, mas o usuario permanece, como proceder pessoal ?

[quote=cssiner]Poxa, eu gostaria de fazer exatamente o OPOSTO do tópico,

possuo uma tablea UNCIONARIO que possui uma chave estrangeira para USUARIO, gostaria de deletar o USUARIO ao mandar excluir o ogbeto do tipo USUARIO que mando ao

FuncionarioDAO.excluir();

no meu caso o funcionario é excluido, mas o usuario permanece, como proceder pessoal ?
[/quote]

Use a anotação deleteOrphan na sua coleção.

ex…

	@OneToOne(fetch = FetchType.EAGER, optional = false, cascade = { javax.persistence.CascadeType.MERGE,
			javax.persistence.CascadeType.PERSIST })
	@Cascade(value = CascadeType.DELETE_ORPHAN)
	private Produto produto = new Produto();

Abraços