Entidades Managed, Transient e Detached no Hibernate e JPA
Distinguir entre os estados de uma entidade no JPA/Hibernate é difícil no início. Um objeto é dito transiente quando não tem representação no banco de dados e nem o EntityManager
o conhece, como abaixo:
Cliente c = new Cliente();
Aqui, qualquer mudança no objeto referido por c
não gerará nenhum tipo de insert ou update no banco de dados. O oposto é quando o objeto existe no banco de dados e o EntityManager
em questão possui uma referência para ele, essa entidade está managed, gerenciada pelo EntityManager
. Considere em
uma referência a um EntityManager
no seguinte exemplo:
Cliente c = new Cliente(); // transiente em.persist(c); // gerenciado
Ou ainda:
Cliente c = em.find(Cliente.class, 1); // gerenciado
Quando uma entidade está managed, qualquer mudança em seu estado (como uma chamada de setter) resultará em uma atualização no banco de dados no momento do commit.
O último caso é quando a entidade representa algo que possivelmente está no banco de dados, mas o EntityManager
o desconhece: a entidade está fora do contexto, detached. Exemplo:
Cliente c = new Cliente(); c.setId(1);
Uma entidade também está detached quando o EntityManager
de onde tiramos esse Cliente
(por exemplo, quando fizemos um find
ou vindo de uma Query
) já não está mais aberta. Qualquer mudança nessa referência obviamente não surtirá efeito no banco de dados. Para que essa mudança faça efeito, isto é, para reattach o entidade, antes precisamos amarrá-la ao contexto de persistência. Repare que no EntityManager
já pode existir uma entidade Cliente
com esse mesmo id, imagine então o que aconteceria se tivéssemos um método que se chamasse reattach
ou update
?
Por isso o método é o merge
. Ele junta a possível entidade com mesmo id que se encontra no EntityManager
com a passada como argumento, e devolve a que está managed. O método merge
não faz reattach. Então:
Cliente c = new Cliente(); c.setId(1); em.merge(c); c.setNome("Cliente com nome alterado");
Não surtirá efeito! Aqui você precisava antes ter pego o que o merge devolveu. Repare na pequena alteração:
Cliente c = new Cliente(); c.setId(1); c = em.merge(c); c.setNome("Cliente com nome alterado");
Pronto. Uma pequena introdução sobre o ciclo de vida de uma entidade em relação a um EntityManager
: transient (a especificação chama de new), managed e detached! Ainda temos o estado removed, quando uma entidade está marcada para a remoção.