JPA OneToOne difference between cascade merge and persist

前端 未结 2 1138
孤街浪徒
孤街浪徒 2020-12-13 05:12

I have the following question. I have 3 entities and I\'m using OneToOne unidirectional:

Entity1

@Entity
public class Entity1 implements Serializable         


        
相关标签:
2条回答
  • 2020-12-13 05:35

    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.

    0 讨论(0)
  • 2020-12-13 05:51

    The behavior you are seeing is the result of two things:

    1. The semantics of the persist and merge operations (calling em.merge(x) will not make x a managed object, but calling em.persist(x) will)
    2. The fact that your entity's id is generated by the database

    em.merge() rundown:

    1. em.merge(entity2); is invoked
      • The merge operation is cascaded to entity1
      • entity1 is copied into a new managed instance, but is not managed itself
    2. em.merge(entity3); is invoked
      • The merge operation is cascaded to entity1 again
      • Because entity1 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 created
    3. The transaction is committed
      • At this point, 3 instances of entity1 exist. Two managed instances created by the merge operations and the initial unmanaged instance
      • The two managed instances are saved in the database

    Note 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() rundown:

    1. em.persist(entity2); is invoked
      • The persist operation is cascaded to entity1
      • entity1 is now a managed object
    2. em.persist(entity3); is invoked
      • The persist operation is cascaded to entity1 again
      • Since entity1 is already managed, the persist operation is ignored
    3. The transaction is committed
      • At this point, only 1 instance of entity1 exists and it is managed.
      • entity1 is saved in the database

    This 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)

    0 讨论(0)
提交回复
热议问题