JPA EntityManager: Por que usar persist() sobre fundir()?

O EntityManager.merge() pode inserir novos objetos e atualizar os existentes.

Por que alguém iria querer utilizar persist() (que só pode criar novos objetos)?

Solução

De qualquer forma, adicionará uma entidade a um PersistenceContext, a diferença está no que você faz com a entidade depois.

Persist toma uma instância de entidade, adiciona-a ao contexto e faz com que essa instância seja gerenciada (ou seja, futuras atualizações da entidade serão rastreadas).

A fusão cria uma nova instância da sua entidade, copia o estado da entidade fornecida e faz com que a nova cópia seja gerida. A instância que você passar não será gerenciada (quaisquer alterações que você fizer não farão parte da transação - a menos que você chame o Merge novamente).

Talvez um exemplo de código ajude.

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

Os Cenários 1 e 3 são mais ou menos equivalentes, mas há algumas situações em que você gostaria de usar o Cenário 2.

Comentários (12)

Eu notei que quando eu usei o em.merge', eu recebi uma declaraçãoSELECT' para cada INSERT', mesmo quando não havia nenhum campo que o JPA estava gerando para mim - o campo chave primário era um UUID que eu mesmo defini. Eu mudei paraem.persist(myEntityObject)e recebi apenas declaraçõesINSERT` então.

Comentários (2)

Eu estava recebendo exceções preguiçosas na minha entidade porque eu estava tentando acessar uma coleção preguiçosa carregada que estava em sessão.

O que eu faria era em um pedido separado, recuperar a entidade da sessão e depois tentar acessar uma coleção na minha página jsp, o que era problemático.

Para aliviar isso, atualizei a mesma entidade no meu controlador e a passei para o meu jsp, embora eu imagine que quando salvei novamente em sessão, ela também estará acessível através de 'SessionScope' e não atirei uma 'LazyLoadingException', uma modificação do exemplo 2:

O seguinte funcionou para mim:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!
Comentários (0)