Entity Manager - criar novo objeto ao invés de editar

Pessoal, to precisando fazer algo bem simples, mas do jeito que fiz não deu certo.

Na minha aplicação, quando o usuário clicar editar, na verdade não quero editar e sim salvar um novo registro.

Ex: tenho um cadastro de Ponto e outro de PontoConfig (um pra muitos), quando alterar um PontoConfig eu mantenho aquelas informações no banco e salvo uma nova (já com as alterações), tenho que fazer isso pra manter um histórico de alterações.

O que fiz? Instanciei um novo objeto e setei nele as informações do outro objeto, ele cria um novo registro, mas o antigo também está sendo alterado, segue o código:

@Begin
public String configPoint() {	
	if(pointConfig.getPointConfigId() != null) {
		pointConfigEdit = new PointConfig(); // instancio um novo objeto (pointConfigEdit) para guardar as informações da alteração
		entityManager.refresh(pointConfig); // recupero o objeto pointConfig
	}	
	return "configPoint";
}

@End
public String savePointConfig() {
	if (pointConfig.getPointConfigId() != null) {
		/* seto em pointConfigEdit as informações de pointConfig */
		pointConfigEdit.setClient(pointConfig.getClient());
		pointConfigEdit.setEquipmentInstallation(pointConfig.getEquipmentInstallation());
		pointConfigEdit.setFormula(pointConfig.getFormula());
		pointConfigEdit.setPoint(point);
		pointConfigEdit.setRegister(pointConfig.getRegister());
		pointConfigEdit.setSensor(pointConfig.getSensor());
		pointConfigEdit.setTeam(pointConfig.getTeam());
		pointConfigEdit.setConfigAlert(pointConfig.getConfigAlert());
		
		entityManager.persist(pointConfigEdit); // persisto apenas pointConfigEdit, mas no banco tá alterando também o pointConfig!!! 
	}
	listPoints();
	return "savePointConfig";		
}

Porque tá dando um merge no pointConfig?
O que tenho que fazer para isso dar certo?

Obrigado!

Provavelmente por causa do seu mapeamento.
PointConfigEdit está como “pai” na relação. Assim quando é editado salva as informações do pointConfig

[quote=Graciano]Provavelmente por causa do seu mapeamento.
PointConfigEdit está como “pai” na relação. Assim quando é editado salva as informações do pointConfig[/quote]
E aí Graciano, na verdade PointConfigEdit é uma nova instancia de PointConfig.

Eu recupero pointConfig através do método refresh, instancio um novo objeto (pointConfigEdit), seto nesse novo objeto as infos de pointConfig e dou um persist no novo objeto.

Provavelmente não seja a maneira correta a se fazer, sabe como eu poderia fazer isso (criar novo objeto ao invés de editar)?

Obrigado

[quote=samerjamal]Pessoal, to precisando fazer algo bem simples, mas do jeito que fiz não deu certo.

Na minha aplicação, quando o usuário clicar editar, na verdade não quero editar e sim salvar um novo registro.

Ex: tenho um cadastro de Ponto e outro de PontoConfig (um pra muitos), quando alterar um PontoConfig eu mantenho aquelas informações no banco e salvo uma nova (já com as alterações), tenho que fazer isso pra manter um histórico de alterações.
![/quote]

Não mantenha o historico na propria tabela. Crie uma tabela de historico. Manipule apenas o mais recente.

[quote=sergiotaborda][quote=samerjamal]Pessoal, to precisando fazer algo bem simples, mas do jeito que fiz não deu certo.

Na minha aplicação, quando o usuário clicar editar, na verdade não quero editar e sim salvar um novo registro.

Ex: tenho um cadastro de Ponto e outro de PontoConfig (um pra muitos), quando alterar um PontoConfig eu mantenho aquelas informações no banco e salvo uma nova (já com as alterações), tenho que fazer isso pra manter um histórico de alterações.
![/quote]

Não mantenha o historico na propria tabela. Crie uma tabela de historico. Manipule apenas o mais recente.[/quote]

Mas essa não é uma decisão minha, é uma especificação :slight_smile:

será que o método clone() resolveria meu problema?

Pessoal, tentei com o método clone(), pelo debug vi que ele tá copiando o objeto em outra instância realmente, só que deu o seguinte erro:

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: org.domain.infralogjava.entity.PointConfig

Segue o código:

@Begin
public String configPoint() {
	
	if(pointConfig.getPointConfigId() != null) {			
		entityManager.refresh(pointConfig);			
	}	
	return "configPoint";
}

@End
public String savePointConfig() throws CloneNotSupportedException {
	if (pointConfig.getPointConfigId() != null) {
		pointConfigEdit = (PointConfig) pointConfig.clone();
		entityManager.persist(pointConfigEdit);
	}
	listPoints();
	return "savePointConfig";		
}

Alguém tem idéia do porque isso ocorre?

sete o campo pointConfigId para null.

Quando o campo @Id do Hibernate não for null ele vai acreditar que o objeto não é novo.

Felagund, eu fiz isso e não deu também, setei antes de clonar, segue o erro:

org.hibernate.HibernateException: identifier of an instance of org.domain.infralogjava.entity.PointConfig was altered from 27 to null

Código:

@Begin
public String configPoint() {
	if(pointConfig.getPointConfigId() != null) {			
		entityManager.refresh(pointConfig);			
	}	
	return "configPoint";
}

@End
public String savePointConfig() throws CloneNotSupportedException {
	if (pointConfig.getPointConfigId() != null) {
		
		pointConfig.setPointConfigId(null);
		pointConfigEdit = (PointConfig) pointConfig.clone();
		
		entityManager.persist(pointConfigEdit);
	}
	listPoints();
	return "savePointConfig";		
}

Vi no debug que está copiando corretamente, e o pointConfigId do pointConfigEdit é criado como null, mas o clone não persiste!!

Ta, então assim cara, esse problema ocorre pq a classe da no EntityManager já, ele acredita que vc esta modificando uma classe ja salva, e ela ja esta no contexto do EM.

Qual a utilidade do refresh na entidade? existem mesmo a necessidde de sincronizar a entidade com o banco antes de salvar?

Experimente remover esse refresh e executar o save.

att

[quote=Felagund]Ta, então assim cara, esse problema ocorre pq a classe da no EntityManager já, ele acredita que vc esta modificando uma classe ja salva, e ela ja esta no contexto do EM.

Qual a utilidade do refresh na entidade? existem mesmo a necessidde de sincronizar a entidade com o banco antes de salvar?

Experimente remover esse refresh e executar o save.

att[/quote]
Então velho, eu tenho que dar refresh sim, pq é uma edição, preciso recuperar as informações.

Uma vez que as recupero, quero copiá-las para uma nova instancia e salvá-las, pois não quero dar update nas informações antigas (quero mante-las inalteradas) e sim salvar as alterações em um novo registro.

Não sei se conseguiu entender e nem sei se é a maneira correta de se fazer isso.

Abraços!

Pra historico, use o ENVERS do hibernate.

Mas, se realmente quer fazer isso na mao, de um clear no entitymanager e depois sete a PK para null/zero

[quote=Paulo Silveira]Pra historico, use o ENVERS do hibernate.

Mas, se realmente quer fazer isso na mao, de um clear no entitymanager e depois sete a PK para null/zero[/quote]
Valeu Paulo e todos que responderam, usando o clear() deu certo.

E usarei o Envers sim, mas para esse caso específico não posso, preciso fazer na unha mesmo.

Abraços!