Hibernate:将级联实体从一个对象移动到另一个对象

时间:2015-01-13 20:06:19

标签: hibernate

考虑一个Team实体,其集合为PlayersTeam映射允许级联合并和保存更新Players

我有一个Team实体,数据库中有4个Players

我的服务允许用户指定TeamPlayer,然后执行以下操作:

  1. 创建现有Team A
  2. 的克隆B.
  3. 从A中删除Player C并将其添加到Team B
  4. 中的集合中

    以上所有操作都在一个只执行数据库查询的事务中完成。它不会执行更新。

    然后使用第二个事务将实体保存到数据库。但是,我不确定如何处理这个问题。

    我现有的逻辑包含以下内容:

    1. 合并Team B,这将有效地保存B队,然后合并到Player C Player C的版本号递增
    2. 合并Team答:但是,由于Hibernate会话的Team实例仍然引用了旧Player C的版本号,因此失败了。
    3. 如何保存这两个实体?我是否必须单独保存Player C并避免使用级联?

1 个答案:

答案 0 :(得分:0)

在存储内容时,合并操作不应该是您的首选操作。它用于将分离的实体与实体管理器合并。非常简短地回顾一下对象可以使用JPA的不同状态(您可能需要阅读此内容):

  • Transient:一个尚未存储在数据库中的新对象(因此对于entitymanager是未知的。)没有设置id。
  • Managed:实体管理员跟踪的对象。托管对象是您在事务范围内使用的对象,一旦提交事务,对托管对象所做的所有更改都将自动存储。
  • Detached:在转换提交后仍可访问的以前管理的对象。 (事务外部的托管对象。)具有id设置。

对于Hibernate / JPA,瞬态和分离对象之间的区别在于它是否具有其id字段的值。

为了将对象存储在数据库中,该方法根据对象的状态而不同。

  • 瞬态:EntityManager.persist。这将存储对象,并使其成为托管对象。
  • 管理:没什么。事务完成后,托管对象会更新。
  • 已分离:EntityManager.merge。由于实体管理器不再识别对象,因此需要重新引入它。但请注意,由于persist-method使您传递给它的对象得到管理,因此merge-method不会。相反,它返回对象的托管副本。

所以,有了这个基础,让我们来看看你在这里要做什么。

首先从EntityManager加载一个对象。鉴于您在事务的上下文中执行此操作,此对象在管理时。然后,复制对象,生成一个新的瞬态对象。然后,对这两个对象进行一些更改。

接下来,提交事务。然后,您的托管对象将被更新,而您的瞬态对象仍然是暂时的。然后,托管对象在事务中幸存,变得分离。然后存储瞬态对象,在这里你应该使用persist-method,而不是merge方法。如果有的话,为了更新你的分离对象(虽然它应该已经更新),你需要将它传递给merge-method。

因此,为了获得适当的级联形式Team to Player,您需要将persist和merge作为级联操作添加。

此外,在制作克隆对象时,请确保不要复制id,因为这会使它与所有Hibernate可以分辨的旧对象相同。

如果A队中的队员C和队B中的队员C有不同的版本号,则它不能是同一个对象。分离对象时可能会发生某些事情,导致两个团队中的玩家C不是同一个对象(但不确定这个......)