如何保留分离的对象?
How do I persist a detached object?
我有一个简单的编辑器 UI 用于在数据库 table 上执行 CRUD。
在 Hibernate 5.1 下,进程为:
- 创建会话。读入数据对象。关闭会话,分离对象。
- 使用分离的对象填充 UI 个小部件。
- 允许用户 add/edit/remove UI 中的条目,修改分离的对象。
- 对用户 "save" 操作:创建新会话。使用 saveOrUpdate() 保存 new/updated 个对象。关闭会话。
- 根据需要重复。
Hibernate 5.2 强烈建议从 Hibernate-native API 迁移到 JPA API。 JPA 不允许您重新附加分离的对象。
有几个解决方法:
- 使用 unwrap 从 JPA EntityManager 获取 Hibernate 会话,并使用它调用 saveOrUpdate。我不喜欢这个选项,因为它依赖于不属于 JPA 的功能。
- 使用 JPA 合并,这将更新持久对象,但我必须确保不破坏任何关联。这给了我同一对象的 2 个副本,一个保留,一个分离......这很乱。
- 执行手动合并操作,将修改的字段从分离对象复制到持久对象。这是额外的工作。
- 在整个过程中保持单个 EntityManager 实例处于活动状态。不幸的是,其他线程可以在该会话仍处于打开状态时执行 CRUD 操作,从而使持久化上下文与数据库不同步 table。所以我也不喜欢这种方法。
有什么好的方法可以做到这一点,还是这些是唯一可用的选择?
JPA does not allow you to reattach detached objects.
JPA 规范定义了 merge()
操作。该操作似乎对实现所描述的用例很有用。
请参考规范:
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.
我想您需要 JPA 合并和乐观锁(实体中基于版本的字段)。如果实体已更改,您将无法将其保存回来。
所以分离它并合并回来(包括版本)。
仍然存在业务逻辑问题,如果对象发生更改该怎么办,使用更新后的值重试或向最终用户发送错误,但最终决定不是技术问题/
我有一个简单的编辑器 UI 用于在数据库 table 上执行 CRUD。 在 Hibernate 5.1 下,进程为:
- 创建会话。读入数据对象。关闭会话,分离对象。
- 使用分离的对象填充 UI 个小部件。
- 允许用户 add/edit/remove UI 中的条目,修改分离的对象。
- 对用户 "save" 操作:创建新会话。使用 saveOrUpdate() 保存 new/updated 个对象。关闭会话。
- 根据需要重复。
Hibernate 5.2 强烈建议从 Hibernate-native API 迁移到 JPA API。 JPA 不允许您重新附加分离的对象。
有几个解决方法:
- 使用 unwrap 从 JPA EntityManager 获取 Hibernate 会话,并使用它调用 saveOrUpdate。我不喜欢这个选项,因为它依赖于不属于 JPA 的功能。
- 使用 JPA 合并,这将更新持久对象,但我必须确保不破坏任何关联。这给了我同一对象的 2 个副本,一个保留,一个分离......这很乱。
- 执行手动合并操作,将修改的字段从分离对象复制到持久对象。这是额外的工作。
- 在整个过程中保持单个 EntityManager 实例处于活动状态。不幸的是,其他线程可以在该会话仍处于打开状态时执行 CRUD 操作,从而使持久化上下文与数据库不同步 table。所以我也不喜欢这种方法。
有什么好的方法可以做到这一点,还是这些是唯一可用的选择?
JPA does not allow you to reattach detached objects.
JPA 规范定义了 merge()
操作。该操作似乎对实现所描述的用例很有用。
请参考规范:
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.
我想您需要 JPA 合并和乐观锁(实体中基于版本的字段)。如果实体已更改,您将无法将其保存回来。
所以分离它并合并回来(包括版本)。
仍然存在业务逻辑问题,如果对象发生更改该怎么办,使用更新后的值重试或向最终用户发送错误,但最终决定不是技术问题/