如何坚持分离的物体?

时间:2017-08-17 11:55:39

标签: java hibernate jpa-2.0

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

  1. 创建会话。读入数据对象。关闭会话,分离对象。
  2. 使用分离的对象,填充UI小部件。
  3. 允许用户在UI中添加/编辑/删除条目,修改分离的对象。
  4. 对用户"保存"操作:创建一个新会话。使用saveOrUpdate()保留新的/更新的对象。关闭会议。
  5. 根据需要重复。
  6. Hibernate 5.2强烈建议从Hibernate-native API迁移到JPA API。 JPA不允许您重新附加分离的对象。

    有几种解决方法:

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

2 个答案:

答案 0 :(得分:2)

  

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

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

请参阅规范:

  

3.2.7.1合并分离的实体状态

     

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

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

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

     

在合并操作期间和/或刷新或提交时,必须由持久性运行时实现检查实体使用的任何版本列。如果没有Version列,则在合并操作期间,持久性提供程序运行时不会执行其他版本检查。

     

- JSR 338: JavaTM Persistence API, Version 2.1, Final Release

答案 1 :(得分:1)

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

分离并合并(包括版本)。

如果更改了对象,使用更新后的值重试或向最终用户发送错误,但仍有业务逻辑问题该怎么办,但最终决定不是技术问题/