问题
I have a simple editor UI for performing CRUD on a database table. Under Hibernate 5.1, the process was:
- Create a session. Read in data objects. Close session, detaching the objects.
- With the detached objects, populate the UI widgets.
- Allow user to add/edit/remove entries in the UI, modifying the detached objects.
- On a user "save" action: Create a new session. Persist new/updated objects with saveOrUpdate(). Close session.
- Repeat as required.
Hibernate 5.2 strongly recommends moving from the Hibernate-native API to the JPA API. JPA does not allow you to reattach detached objects.
There are a couple of workarounds:
- Use unwrap to get the Hibernate session from the JPA EntityManager, and use it to call saveOrUpdate. I don't like this option because it relies on functionality that is not part of the JPA.
- Use JPA merge, which will update the persisted object, although I've got to ensure I don't break any associations. This gives me 2 copies of the same object, one persisted, one detached... which is messy.
- Perform a manual merge operation, copying modified fields from the detached object to the persisted object. This is extra work.
- Keep a single EntityManager instance alive through the whole process. Unfortunately, other threads could perform CRUD operations while this session is still open, taking the persisted context out of sync with the database table. So I'm not a fan of this approach either.
Is there any good way to do this, or are these the only options available?
回答1:
JPA does not allow you to reattach detached objects.
The JPA specification defines the merge()
operation. The operation seems to be useful to implement the described use case.
Please refer to the specification:
3.2.7.1 Merging Detached Entity State
The merge operation allows for the propagation of state from detached entities onto persistent entities managed by the entity manager. 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.
The persistence provider must not merge fields marked LAZY that have not been fetched: it must ignore such fields when merging.
Any Version columns used by the entity must be checked by the persistence runtime implementation during the merge operation and/or at flush or commit time. In the absence of Version columns there is no additional version checking done by the persistence provider runtime during the merge operation.
— JSR 338: JavaTM Persistence API, Version 2.1, Final Release.
回答2:
I guess you need JPA merge together with optimistic locks (Version based field in your entity). If the entity was changed you won't be able to save it back.
So detach it and merge back (including the version).
There is still business logic question what to do if object is changed, retry with the updated values or send an error to end user but final decision is not technology issue/
来源:https://stackoverflow.com/questions/45734475/how-do-i-persist-a-detached-object