【问题标题】:How do I persist a detached object?如何持久化分离的对象?
【发布时间】:2018-01-25 19:57:10
【问题描述】:

我有一个简单的编辑器 UI,用于在数据库表上执行 CRUD。 在 Hibernate 5.1 下,该过程是:

  1. 创建一个会话。读入数据对象。关闭会话,分离对象。
  2. 使用分离的对象填充 UI 小部件。
  3. 允许用户在 UI 中添加/编辑/删除条目,修改分离的对象。
  4. 在用户“保存”操作时:创建一个新会话。使用 saveOrUpdate() 保存新的/更新的对象。关闭会话。
  5. 根据需要重复。

Hibernate 5.2 强烈建议从 Hibernate-native API 迁移到 JPA API。 JPA 不允许您重新附加分离的对象。

有几种解决方法:

  1. 使用 unwrap 从 JPA EntityManager 获取 Hibernate 会话,并使用它来调用 saveOrUpdate。我不喜欢这个选项,因为它依赖于不属于 JPA 的功能。
  2. 使用 JPA 合并,这将更新持久对象,但我必须确保不会破坏任何关联。这给了我同一个对象的 2 个副本,一个是持久的,一个是分离的……这很混乱。
  3. 执行手动合并操作,将已修改的字段从分离对象复制到持久对象。这是额外的工作。
  4. 在整个过程中保持单个 EntityManager 实例处于活动状态。不幸的是,其他线程可以在此会话仍处于打开状态时执行 CRUD 操作,从而使持久化上下文与数据库表不同步。所以我也不喜欢这种方法。

有什么好的方法可以做到这一点,或者这些是唯一可用的选项吗?

【问题讨论】:

    标签: java hibernate jpa-2.0


    【解决方案1】:

    JPA 不允许您重新附加分离的对象。

    JPA 规范定义了merge() 操作。该操作似乎对实现所描述的用例很有用。

    请参考规范:

    3.2.7.1 合并分离实体状态

    合并操作允许将状态从分离的实体传播到由实体管理器管理的持久实体上。应用于实体 X 的合并操作的语义如下:

    • 如果 X 是分离实体,则将 X 的状态复制到具有相同身份的预先存在的托管实体实例 X' 或创建 X 的新托管副本 X'。
    • 如果 X 是一个新的实体实例,则创建一个新的托管实体实例 X',并将 X 的状态复制到新的托管实体实例 X'。
    • 如果 X 是已移除的实体实例,则合并操作将抛出 IllegalArgumentException(否则事务提交将失败)。
    • 如果 X 是托管实体,则合并操作将忽略它,但是,如果这些关系已使用级联元素值 cascade=MERGE 或 cascade=ALL 进行注释,则合并操作将级联到由 X 的关系引用的实体注释。
    • 对于由来自 X 且具有级联元素值 cascade=MERGE 或 cascade=ALL 的关系引用的所有实体 Y,Y 将递归地合并为 Y'。对于由 X 引用的所有此类 Y,X' 设置为引用 Y'。 (请注意,如果 X 是托管的,则 X 与 X' 是同一个对象。)
    • 如果 X 是合并到 X' 的实体,并引用另一个实体 Y,其中未指定 cascade=MERGE 或 cascade=ALL,则从 X' 导航相同关联会产生对托管对象 Y 的引用' 与 Y 具有相同的持久标识。

    持久性提供程序不得合并标记为 LAZY 且尚未获取的字段:合并时必须忽略此类字段。

    实体使用的任何版本列都必须在合并操作期间和/或在刷新或提交时由持久性运行时实现检查。在没有版本列的情况下,持久性提供程序运行时不会在合并操作期间进行额外的版本检查。

    ——JSR 338: JavaTM Persistence API, Version 2.1, Final Release.

    【讨论】:

    • 同意合并是这里的最佳选择。 +1
    【解决方案2】:

    我猜您需要将 JPA 与乐观锁(实体中基于版本的字段)合并在一起。如果实体已更改,您将无法将其保存回来。

    所以分离它并合并回来(包括版本)。

    如果对象被更改,仍然存在业务逻辑问题,使用更新的值重试或向最终用户发送错误但最终决定不是技术问题/

    【讨论】:

      猜你喜欢
      • 2012-05-14
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 1970-01-01
      • 2019-03-02
      • 2021-02-02
      • 1970-01-01
      相关资源
      最近更新 更多