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



考虑一个具有Players集合的Team实体。Team映射允许级联合并并将更新保存到Players

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

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

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

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

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

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

  1. 合并Team B,这将有效地保存团队 B,然后合并Player C。 Player C 的版本号递增
  2. 合并Team A。但是,此操作会失败,因为休眠会话的 Team A 实例仍具有对旧 Player C 版本号的引用。

如何保存这两个实体?我是否必须单独保存Player C 并避免使用级联?

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

  • 瞬态:尚未存储在数据库中的新对象(因此实体管理器不知道)。没有设置 id。
  • 托管:实体管理器跟踪的对象。托管对象是您在事务范围内使用的对象,对托管对象所做的所有更改将在事务提交后自动存储。
  • 已分离:以前托管的对象,在转换提交后仍可访问。(事务外部的托管对象。设置了 ID。

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

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

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

因此,在此基础上,让我们看看您在这里要做什么。

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

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

因此,为了从团队到玩家获得正确的级联,您需要将持久化和合并添加为级联操作。

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

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

最新更新