Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA : What is the behaviour of merge with lazy initialized collection?

Tags:

jpa

jpa-2.0

Here are the sequences leading to the question :

  1. I have a Team record, and 3 Player records in the database. Team entity has a List that is using FetchType.LAZY, CascadeType.ALL
  2. The search button on the webui is clicked
  3. Query in the server side using JPA query is invoked, finding all the Team records, in this case, only 1 record of the team entity returned from the query (which has a proxy of the list of player entities)
  4. Map this teamEntity to a DTO, and return this DTO to the webui, skipping the mapping of the list of player entities
  5. Webui renders the DTO in a html form, ready to receive modifications from the user
  6. User modifies the team's properties, like the date of when it's founded
  7. The save button on the webui is clicked
  8. Converting the DTO to the team entity, to be used to update the already existing team record
  9. But in this case, if i were to use the em.merge(teamEntity), the team record will be updated, but what will happen to the list of players ? Because when converting from DTO to the team entity, the teamEntity has an empty list of players entities. And after merging, i notice that the teamEntity has 0 size of the details. But after refreshing that entity, em.refresh(teamEntity), it will return 3 of the detail size.

Im confused on :

  1. Why is it the size is 0 after merged ? It's like not representing the record anymore
  2. Before doing the test, i was thinking that the details will be removed since im merging a teamEntity with an empty detail.

Please enlighten me :)

Thank you !

like image 784
Albert Gan Avatar asked Mar 09 '11 10:03

Albert Gan


People also ask

How does merge work in JPA?

JPA's merge method copies the state of a detached entity to a managed instance of the same entity. Hibernate, therefore, executes an SQL SELECT statement to retrieve a managed entity from the database.

What is the result of lazy loading strategy in hibernate degrade performance?

Now, Hibernate can use lazy loading, which means it will load only the required classes, not all classes. It prevents a huge load since the entity is loaded only once when necessary. Lazy loading improves performance by avoiding unnecessary computation and reduce memory requirements.

Which of the following attribute is used to create lazy association between two classes?

To enable lazy loading explicitly you must use “fetch = FetchType. LAZY” on an association that you want to lazy load when you are using hibernate annotations.


1 Answers

JPA Specification says:

The semantics of the merge operation applied to an entity X are as follows:

  • If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.

  • 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'.

  • If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail).

  • If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the cascade element value cascade=MERGE or cascade=ALL annotation.

  • 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'.)

  • If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.

As you can see, there is no magic here. The state of detached instance is copied into the newly created managed instance. Since your detached instance has an empty list, managed instance would have it too.

Further behaviour depends on ownership of relationship, since representation in the database reflects the owning side of relationship:

  • If Team is the owning side, relationships between Team and Players will be destroyed during flush (but Player itself would survive unless you have orphanRemoval = true on your relationship).
  • Otherwise having the empty list in Team doesn't affect the database.

If you refresh the Team before flushing the context, all properties of Team are rewritten by values from the database, therefore list of Players is restored (since the empty list of players wasn't flushed yet).

If you call flush() before calling refresh(), and Team is the owning side, list will be empty, since destruction of relationships was propagated to the database during flush().

like image 158
axtavt Avatar answered Nov 21 '22 18:11

axtavt