3
respostas

Merge no Atualizar e no Remover

Vou puxar a dúvida de 4 anos atrás da Camila de volta.

public void atualizar(Categoria categoria) {
       this.em.merge(categoria);
    }


    public void remover(Categoria categoria) {
        categoria = em.merge(categoria);
        this.em.remove(categoria);
    }

Por qual motivo para remover é preciso reatribuir a categoria e para atualizar não? Sendo que no vídeo anterior, houve um exemplo em que havia sido disparado um clear no entity manager e foi preciso reatribuir para realizar o update.

3 respostas

Oi, Guilherme! Como vai?

No JPA, uma entidade pode estar em diferentes estados: transient, managed, detached e removed. Quando você está tentando remover uma entidade, ela precisa estar no estado managed para que o EntityManager possa gerenciá-la corretamente e, consequentemente, removê-la do banco de dados.

No método atualizar, você usa o merge para garantir que a entidade está no estado managed. O merge pega uma entidade detached e a transforma em uma entidade managed, mas não é necessário reatribuir a entidade ao fazer um update, porque o merge já garante que a entidade está no estado correto para ser atualizada.

Já no método remover, você precisa garantir que a entidade está no estado managed antes de chamar o remove. Se a entidade estiver detached, o remove não funcionará e resultará em uma exceção. Por isso, você usa o merge e reatribui a entidade: categoria = em.merge(categoria);. Isso garante que a entidade está no estado managed e pode ser removida com segurança.

Então, a diferença está no fato de que, ao remover, precisamos ter certeza de que estamos lidando com a instância managed correta, daí a necessidade de reatribuir a entidade após o merge.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Certo.

Mas na aula Estados no Update da Entidade, a partir de 5:31, é dito que para o update é necessário refazer a atribuição. Por que naquele caso precisa e neste não precisa? Não consigo ver qualquer diferença no funcionamento de ambos.

Oi, Guilherme! Perdão pela demora em responder.

A diferença está no retorno do merge. O merge(categoria) não transforma a mesma instância que você já tinha em gerenciada. Ele devolve outra instância, agora no estado managed.

No caso do remove, isso é obrigatório porque o método remove() só aceita uma entidade gerenciada. Então, se você fizer assim:


em.remove(categoria);

E essa categoria estiver detached, a remoção falha. Por isso é necessário reatribuir:


categoria = em.merge(categoria);
em.remove(categoria);

Neste ponto, o remove() será executado sobre a instância que o JPA está gerenciando. Já no update, depende de como o código continua depois do merge. Se o método faz só isto:


em.merge(categoria);

não é necessário reatribuir, porque o próprio merge já copia os dados da entidade destacada para a instância gerenciada, e o JPA sincroniza isso no banco no commit ou no flush.

Mas, na aula em que houve clear(), foi preciso reatribuir porque, depois do clear, a instância antiga deixou de ser gerenciada. Então, para continuar trabalhando com a entidade dentro do contexto de persistência, era necessário usar a referência retornada pelo merge:


categoria = em.merge(categoria);

O ponto importante é este:

  • Sem reatribuir no update: funciona quando você só quer mandar o JPA mesclar os dados e encerrar ali.
  • Com reatribuição no update: necessário quando você ainda vai usar a entidade depois do merge, porque a instância retornada é a que está managed.
  • No remove, a reatribuição é necessária porque o remove() precisa receber justamente essa instância managed.

Veja este exemplo:


Categoria categoriaDetached = new Categoria();
categoriaDetached.setId(1L);
categoriaDetached.setNome("Casa");

Categoria categoriaManaged = em.merge(categoriaDetached);

Depois disso:

  • categoriaDetached continua detached
  • categoriaManaged fica managed

Então, para atualizar, pode bastar:


em.merge(categoriaDetached);

Mas, para remover, precisa ser:


Categoria categoriaManaged = em.merge(categoriaDetached);
em.remove(categoriaManaged);

Ou seja, a diferença não está no funcionamento do merge, e sim no que cada operação exige depois dele. O update pode acontecer só com a mesclagem dos dados. Já o remove exige a instância gerenciada retornada pelo merge.

Fico à disposição!