Entidades Managed, Transient e Detached no Hibernate e JPA
Por Paulo Silveira em 23/11/06Esse blog tem recebido uma média alta de comentários (agradecemos!), em alguns posts temos mais de dez pessoas diferentes dando sugestões. O patinho feio é meu longo post sobre as exceptions que mais acontecem quando desenvolvemos com Hibernate e JPA, talvez por alguns casos não serem tão comuns assim, e porque JPA ainda está recente.
Apesar de terem reclamado que isto está parecendo um livro de Hibernate, vou escrever aqui a introdução mais curta da história da JPA, baseado na palestra que dei sobre esse assunto no ConexãoJava e com a ajuda do Fábio Kung e do Nico Steppat para deixá-la minimal.
Um objeto é dito transiente quando não tem representação no banco de dados e nem o EntityManager o conhece. Exemplo:
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.
Sua palestra tão elogiada será disponibilizada?
Comment by Luca Bastos — November 24, 2006 @ 6:01 am
Olá apesar da grande quantidade de textos sobre hibernate/JPA, eu acho extremamente válido, é só ver no guj, hibernate responde por uma fatia considerável das dúvidas diárias (até acho q deveria ter um tópico só para hibernate, hehe), então qq ajuda é sempre bem vinda nesse assunto.
Continuem assim!
Comment by Edufa — November 24, 2006 @ 7:22 am
“Apesar de terem reclamado que isto está parecendo um livro de Hibernate, vou escrever aqui a introdução mais curta da história da JPA, baseado na palestra que dei sobre esse assunto no ConexãoJava”
Muito boa, por sinal. Pena que não peguei desde o começo. PS: A Caelum já ta com curso baseada nela né? Não? Tão esperando o que?
Comment by Diego Pires Plentz — November 26, 2006 @ 1:24 pm
No curso as entidades são mapeadas com as anotações do javax.persistence, mas ainda usamos Session/SessionFactory !
Comment by Fabio Kung — November 29, 2006 @ 5:58 am
Só fiquei com uma dúvida. Você está mostrando que, para recuperar um objeto detached, você usou o merge, mas o merge também pode ser utilizado para fazer um update em um objeto, portanto, ao utilizarmos para recuperar, como ele vai saber que não deve ser feito também o update?
Comment by Pamela — March 10, 2007 @ 9:33 am
Muito boa introdução, parabens!
Amigo eu gostaria de saber o que eu devo fazer quando quero recuperar um objeto que já foi alterado mas ainda não foi enviado para o banco, da forma que ele está no banco. Ou seja: eu quero comparar o objeto da memória com o que está no banco, mas quando eu faço uma consulta no entityManager ele me retorna uma referencia para o objeto da memorio… assim eu não consigo acessar o que está no banco… como eu faço isso??
Comment by Jean Michel Baldessar — May 27, 2008 @ 5:35 pm
jean, chame o .clear() no seu entitymanager, assim na proxima invocacao ele nao vai tirar do 1st level cache
Comment by Paulo Silveira — May 27, 2008 @ 5:40 pm
massa d+++++ !!!!!!!!!!!!!! para que serve msm ???
achei bonito o codigo,,, só isso
Comment by bunny — November 24, 2008 @ 12:29 am