Diferenças entre em.merge(Object o) e em.refresh(Object o)

Olá,

Eu desconfio que essa seja uma pergunta de resposta muito simples, porém para mim, ela é necessária.
Estou fazendo as primeiras utilizações do JPA e não consegui entender a diferença entre esses dois métodos do EntityManager.

Qual deles faz realmente UPDATE no Banco de Dados?

Caso os dois façam UPDATE, por que existem os dois?

Agora a coisa complicou um pouco mais pra mim.
Criei três classes:

Usuario
Armamento
Cautela

Uma cautela é a união de um usuário com vários armamentos, além da data da cautela e um flag que condiciona se a cautela está aberta ou não.

Para tanto essa é a cara da Cautela

@Entity
public class Cautela {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @OneToOne
    private Usuario usuario;
    @OneToMany
    private Collection<Armamento> materiaisCautelados;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dataCautela;
    @Temporal(TemporalType.TIMESTAMP)
    private Date dataEntrega;
    private boolean opened;

Tentei persistir de várias formas uma cautela, consegui de duas formas:

  1. Criava uma cautela, atribuía-lhe os objetos Usuario e a lista de Armamento e persistia-os em cascata (com CascadeType.PERSIST) de uma só vez.
    Porém dessa forma não é interessante, pois é contrária à regra de negócio do meu sistema, pois os Usuarios e os Armamentos são persistidos individualmente antes de qualquer cautela.
  2. consegui com em.merge(Cautela c).
    Eu sou muito preocupado com o porquê das coisas e já estava intrigado com a diferença entre merge() e refresh() e agora mais essa.

Isso é culpa desses tutoriais que cobrem os assuntos de forma muito superficial.
Ex:
Para persistir um objeto ‘o’ no banco de dados usando JPA, basta fazer
em.persist(o)

Olá

O método refresh() atualiza o estado da instância a partir do banco de dados. Trocando em miúdos, copia os dados do banco e joga nos atributos da instância.
O método merge() atualiza a instância no banco de dados, transferindo seu estado para o banco. Ou seja, quem realmente faz update é o método merge().
A única semelhança entre o comportamento dos dois métodos é que ambos tornam a instância managed, significando que seu estado está sincronizado com o contexto de persistência.

Talvez seja hora de rever suas fontes. Estude a documentação de referência do Hibernate.

ok ok tnaires,

Sobre as minhas fontes, você há de convir que não existe um CREDIBILIDADÔMETRO pra me ajudar a escolher as mais confiáveis.
E também tenho uma pergunta.
Eu estou usando JPA e não Hibernate. A documentação do Hibernate me ajuda mesmo assim?

E sobre o persist e o merge?
Os dois salvam objetos no BD.

[quote=tnaires]A única semelhança entre o comportamento dos dois métodos é que ambos tornam a instância managed, significando que seu estado está sincronizado com o contexto de persistência.
[/quote]

Isso mesmo!

So lembrando um detalhe técnico: o merge devolve um objeto managed a partir de um objeto (que pode estar managed ou nao), que é diferente de tornar a instancia em managed. Por isso que o merge devolve T (esse sim é managed). O refresh nao aceita objetos detached, só managed. Algumas implementações fazem algo um pouquinho diferente (hibernate deixa dar refresh em detached, mas a especificação não).

Ajuda sim, para Hibernate veja a referência do Hibernate Core. Para JPA veja a referência dos módulos Annotations e EntityManager.

[quote=Cocota]E sobre o persist e o merge?
Os dois salvam objetos no BD.[/quote]
O persist() recebe uma instância no estado transient e a torna persistente - consequentemente managed. Ou seja, para inserir dados use persist().

Exato. Se você tem uma instância detached e quer torná-la managed, merge() é o método correto a se usar.