I have the following question. I have 3 entities and I\'m using OneToOne unidirectional:
Entity1
@Entity
public class Entity1 implements Serializable
I would not dream to challenge the uber answer of DannyMo, but I wanted to make an addition:
Persist and merge are designed as a way to keep one managed instance of certain object.
If you use persist it means the object does not exist yet, so making it a unique managed instance doesn't hurt.
When you use merge, you take into consideration that a managed instance of the object may already exist. You don't wanna replace that unique managed instance, because some other object might reference it, believing it is the managed object.
If you want to make operations on the object after the merge, the correct merge would look like this:
managedObject = em.merge(object); // or just object = em.merge(object)
//You cannot do it with persist since it returns null
If you tried to check if managedObject
and object
points to the same object instance checking if(managedObject == object)
you will get false (true is possible when you use merge on already managed object and the operation is ignored).
If you use merge on outdated version of object, which you passed as argument to the previous merge, jpa doesn't know how to find the right object since it has yet no id. It is assumed that it is a new object and new managed instance will be created.
I'm quite a rookie. Please correct me if I am wrong anywhere.
The behavior you are seeing is the result of two things:
em.merge(x)
will not make x
a managed object, but calling em.persist(x)
will)em.merge(entity2);
is invoked
entity1
entity1
is copied into a new managed instance, but is not managed itselfem.merge(entity3);
is invoked
entity1
againentity1
is still unmanaged and doesn't have an identifier, it cannot be matched to the existing managed instance created by the previous merge. The result is that another new instance is createdentity1
exist. Two managed instances created by the merge operations and the initial unmanaged instanceNote that if your entity had an explicit id, then the second merge would not have created a new instance, but instead would have copied entity1
into the managed instance that already existed. Also, if you instead tried to merge the already managed instance, then the second merge operation would have been ignored.
em.persist(entity2);
is invoked
entity1
entity1
is now a managed objectem.persist(entity3);
is invoked
entity1
againentity1
is already managed, the persist operation is ignoredentity1
exists and it is managed.entity1
is saved in the databaseThis behavior is defined in the JPA 2.0 Specification section 3.2.7.1 Merging Detached Entity State:
The semantics of the merge operation applied to an entity X are as follows:
- If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.
- For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.)
- [...]
and section 3.2.2 Persisting and Entity Instance:
The semantics of the persist operation, applied to an entity X are as follows:
- If X is a new entity, it becomes managed. The entity X will be entered into the database at or before transaction commit or as a result of the flush operation.
- If X is a preexisting managed entity, it is ignored by the persist operation. [...]
- [...]
See also: When does the JPA set a @GeneratedValue @Id)