JPA - Problema para persistir e atualizar do dados no BD

Bom dia a todos

Estou com o seguinte problema: criei um método genérico para inserção e atualização dos dados usando JPA. Até a parte de inserir novos dados no BD vai tudo bem, porém quando vou tentar atualizar algum dado, aí a coisa fica feia, tipo :shock: . O código que eu criei é o seguinte:


public boolean salvar(E e) {

		logger.debug("Iniciando a tarefa de gravação do objeto " + e.getClass().getSimpleName());
		EntityTransaction trans = getEm().getTransaction();

		trans.begin();

		logger.debug("Verificando se os dados ja existem...");

		if(getEm().contains(e)){
			logger.debug("Atualizando a tabela");
			getEm().merge(e);
		}else{
			logger.debug("Inserindo novos dados na tabela");
			getEm().persist(e);
		}
		trans.commit();
		return true;
	}

e o erro é:


Exception occurred during event dispatching:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: dao.TipoAtributo
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300)
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306)
	at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:871)
	at dao.ClasseModelDAO.salvar(ClasseModelDAO.java:128)
	at control.CrtTipoAtributo.salvar(CrtTipoAtributo.java:149)
	at control.CrtTipoAtributo.actionPerformed(CrtTipoAtributo.java:34)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.Dialog$1.run(Unknown Source)
	at java.awt.Dialog$3.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.awt.Dialog.show(Unknown Source)
	at java.awt.Component.show(Unknown Source)
	at java.awt.Component.setVisible(Unknown Source)
	at java.awt.Window.setVisible(Unknown Source)
	at java.awt.Dialog.setVisible(Unknown Source)
	at forms.FrmTipoAtributo.<init>(FrmTipoAtributo.java:56)
	at control.CrtProjeto.evenPopMenu(CrtProjeto.java:93)
	at control.CrtProjeto.actionPerformed(CrtProjeto.java:47)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.AbstractButton.doClick(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI$Handler.menuDragMouseReleased(Unknown Source)
	at javax.swing.JMenuItem.fireMenuDragMouseReleased(Unknown Source)
	at javax.swing.JMenuItem.processMenuDragMouseEvent(Unknown Source)
	at javax.swing.JMenuItem.processMouseEvent(Unknown Source)
	at javax.swing.MenuSelectionManager.processMouseEvent(Unknown Source)
	at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: dao.TipoAtributo
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)
	at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:78)
	at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:844)
	at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:819)
	at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:823)
	at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:865)
	... 69 more

Para criar este método eu adaptei do seguinte código:

public void save(Cliente cliente){ EntityTransaction trans = em.getTransaction(); trans.begin(); //Se o cliente ja existe if(em.contains(cliente)){ //Atualiza o cliente em.merge(cliente); }else{ //Senao cria um novo em.persist(cliente); } trans.commit(); } .

Pelo que verifiquei o problema pode ser por causa cache, pois não encontra no EntityManager (“em”). Outra possível causa é o fato do objeto estar no estado “datached” (não entendi o que significa, parece que o objeto está fora de sincronia com o banco), ou ainda, achei na net, o problema poderia ser porque a classe está marcada para gerar códigos automaticamente (o atributo chave possui tanto a anotação “@Id”, quanto “@GeneratedValue”). Acho está último hipótese meio estranha, mas como não entendo muita coisa de hibernate e de JPA entendo menos ainda, estou considerando.

Agradeço a todos que puderem ajudar.

Inté…

Seu objeto tem relacionamentos com outros objetos?

Parece ser este o erro.

Se você tem uma Classe Carro e ela tem o atributo Pessoa dono, o dono tem que está attached (sincronizado) com a transação.

Provalvemente deve ser o caso comentado acima, poste a classe Cliente.

Tudo bom Jakefrog

Realmente o problema pode ter a ver com isto. Você mencionou a ligação das classes e daí tentei atualizar os dados de outra classe, que não possui ligação com nenhuma outra e deu certo. Daí que vem a parte estranha, eu voltei na classe que estava dando problema e comentei todos os atributos que eram do tipo de outras classes, no caso um List e um enum, queria ver qual dos dois estava dando problema, só que no fim deu o mesmo erro. Se ajudar abaixo segue o código das classes:

public class TipoAtributo {

	@Id
	@GeneratedValue
	private long codigo;
	public final static String TAG_CODIGO = "codigo";
	
	@Column(name = "nome", length = 30)
	private String nome;
	public final static String TAG_NOME = "nome";
	
	@Column(name = "descricao", length = 300)
	private String descricao;
	public final static String TAG_DESCRICAO = "descricao";

	@Column(name = "tipoBase")
	@Enumerated(EnumType.ORDINAL)
	private TipoAtributoBase tipo;
	public final static String TAG_TIPO = "tipo";
	
	@OneToMany(mappedBy="tipo")
	private List<ValorPropriedade> valorPropriedades = new ArrayList<ValorPropriedade>();
	
	public final static String TAG_VALOR_PROPRIEDADES = "valorPropriedades";
	public final static String TAG_TIPO_ATRIBUTO = "tipo_atributo";
       
       //get/set/add/remove

E o enum:

package dao;

public enum TipoAtributoBase {

	BOOLEAN, BYTE, CHAR, CLASSE, DOUBLE, FLOAT, INT, LONG, SHORT, STRING, OUTRO 
	
}

Oi Diegobrandao

A classe cliente era do exemplo que eu adaptei para criar o método genérico. A classe problemática é a TipoAtributo.

Vlw

Os objetos da lista “valorPropriedades” já estao persistidos? Caso contrário vc precisa adicionar um “cascade”. Ex: cascade = CascadeType.ALL

Oi Diegobrandao

Foi mal a demora, tive um problemão para resolver. Os objetos da lista “valorPropriedades” ainda não estão persistidos, para falar a verdade, esse atributo é uma curiosidade que eu tenho a respeito do “mappedby”, que eu não sei como que funciona, e ao bem da verdade o relacionamento certo é ValorPropriedade possui um atributo do tipo TipoAtributo. Só que como eu tinha mencionado anteriormente, eu fiz um teste no qual tanto a lista “valorPropriedade” quanto o enum “tipo” estavam comentados. Se bem que eu não se sei se o fato dos mesmos estarem comentados, tanto atributo quanto método, realmente interfere em alguma coisa, pois eu achei que fazendo assim os campos referentes ao “tipo” iam ser apagados do banco, mas continuam todos iguais.

Obs: Acabei de fazer mais um teste, comentando apenas as linhas referentes a lista “valorPropriedade” e as anotações desta e o erro continua persistindo.

Vocês que entedem mais de JPA e Hibernate, como é que fazem, que nem no meu tá muito genérico porque sou preguiçoso, mas posso alterar o código se for mais tranquilo, dá um pouco mais de trabalho, mas é tranks.

Vlw