Atualizar entidade antes da persistência no BD

8 respostas
king_of_gods

Amigos,

Estou com o seguinte problema:

- Tenho um cadastro de Pessoas. A inclusão de pessoa funciona sem problemas. O problema acontece a partir daí, qualquer outra "alteração" tenho dificuldade por causa dos campos de Sistema.

@MappedSuperclass
public class Sistema {
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;

	@Column(nullable=false)
	private Date dataCriacao;

	@Column(nullable=false)
	private Date dataUltimaAlteracao;
	
	@Version
	@Column(nullable=false)
	private Long version;
	
	@Column(nullable=false)
	private Boolean status;
@Entity
public class Pessoa extends Sistema {
	
	@Column
	@NotNull
	@NotEmpty
	private String nomePessoa;
	
	@Enumerated(value=EnumType.STRING)
	@Column
	@NotNull
	private TipoPessoa tipoPessoa;
	
	@Column
	@NotNull
	@NotEmpty
	private String cpf;
	
	@Enumerated(value=EnumType.STRING)
	@NotNull
	private Sexo sexo;

	@Enumerated(value=EnumType.STRING)
	@Column
	@NotNull
	private EstadoCivil estadoCivil;
	
	@Column
	@NotNull
	@Past
	private Date dataNascimento;
	
	@ManyToOne
	@NotNull
	private Profissao profissao;
	
	@OneToOne
	@NotNull
	@Valid
	private Endereco endereco;
	
	@OneToMany(mappedBy="pessoa")
	private List<Telefone> telefones;
	
	@Column
	@Email
	private String email;

Eu levo pra tela, apenas o ID da Pessoa. Eu passo pela minha lógica e no momento da gravação eu estou procurando uma forma de atualizar os atributos de sistema em pessoa.

public abstract class SistemaDAO<T> implements SistemaRepository<T>{
	/**/
public void update(T t) {
		if (t instanceof Sistema) {
			refreshSistema(t);
			
			Sistema sistema = (Sistema) t;
			
			sistema.setDataUltimaAlteracao(new Date());
		}

		session.update(t);
	}
	
	@SuppressWarnings("unchecked")
	private void refreshSistema(T t) {
		try {
			T newT = (T) t.getClass().newInstance();
			((Sistema) newT).setId(((Sistema) t).getId());
			
			this.refresh(newT);
			
			((Sistema) t).setDataCriacao(((Sistema) newT).getDataCriacao());
			((Sistema) t).setDataUltimaAlteracao(((Sistema) newT).getDataUltimaAlteracao());
			((Sistema) t).setStatus(((Sistema) newT).getStatus());
			((Sistema) t).setVersion(((Sistema) newT).getVersion());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**/
}

O erro que ele me gera:

Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [br.com.sistema.model.endereco.Endereco#1]
	at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:637)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:305)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:246)
	at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:57)
	at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
	at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:734)
	at org.hibernate.impl.SessionImpl.update(SessionImpl.java:722)
	at org.hibernate.impl.SessionImpl.update(SessionImpl.java:714)
	at br.com.sistema.dao.SistemaDAO.update(SistemaDAO.java:46)
	at br.com.sistema.controller.PessoaController.adicionar(PessoaController.java:186)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:57)
	... 43 more

Agradeço a ajuda desde já :)

8 Respostas

Lucas_Cavalcanti

dá um evict no newT depois do refresh…

o problema é que vc fez um refresh, que colocou um objeto na sessão, e depois tentou fazer um update de um outro objeto com o mesmo id…

king_of_gods

Funcionou valeu :smiley:

Paulo_Silveira

Lucas Cavalcanti:
dá um evict no newT depois do refresh…

o problema é que vc fez um refresh, que colocou um objeto na sessão, e depois tentou fazer um update de um outro objeto com o mesmo id…

Lucas, curioso que ele ja tinha tentado com merge. Nesse caso nao deveria funcionar?

Lucas_Cavalcanti

Paulo Silveira:
Lucas Cavalcanti:
dá um evict no newT depois do refresh…

o problema é que vc fez um refresh, que colocou um objeto na sessão, e depois tentou fazer um update de um outro objeto com o mesmo id…

Lucas, curioso que ele ja tinha tentado com merge. Nesse caso nao deveria funcionar?


com dois objetos de mesmo id não…
1o objeto é o do refresh (ou do load)
2o objeto é o transient que foi usado pra fazer o update

Carlos_ds_jar

Paulo Silveira:
Lucas Cavalcanti:
dá um evict no newT depois do refresh…

o problema é que vc fez um refresh, que colocou um objeto na sessão, e depois tentou fazer um update de um outro objeto com o mesmo id…

Lucas, curioso que ele ja tinha tentado com merge. Nesse caso nao deveria funcionar?


Desculpe entrar na discussão, mas eu já uso JPA a algum tempo, se eu estiver falando besteira por favor me corrijam, mas pelo que eu sei o merge funciona para mesclar objetos um transiente e outro persistente desde que com id igual de forma que acho que se enquadraria perfeitamente à situação :idea:

Lucas_Cavalcanti

é bem possivel que eu esteja falando besteira então =S

Carlos_ds_jar

Exemplo de uso do merge:

public String atualizarCaixa(Integer codigo, String nome, String login, String senha, String telefone) {
        Caixa cai = em.find(Caixa.class, codigo); //Faz o load do objeto com o ID passado
        cai.setNome(nome); //Alterando seu campo passa a ser um um objeto transiente com o ID passsado
        cai.setLogin(login);
        cai.setSenha(senha);
        cai.setTelefone(telefone);
        em.merge(cai); //Após mesclar o objeto ele passa a ser persistente, ou seja o seu tempo de vida passa a poder ser maior do que o tempo de vida da execução em questão
        return "cadastrado";
    }
Paulo_Silveira

Carlos, nesse seu caso voce nem precisava ter chamado o merge, ja que o objeto esta managed. Ia funcionar mesmo sem o merge (iria ocorrer o update).

So é necessario chamar o merge quando o objeto esta detached.

Criado 9 de agosto de 2010
Ultima resposta 10 de ago. de 2010
Respostas 8
Participantes 4