1

TLDR:将休眠版本从 3. 切换到 5 .. 现在,与仅在一个类中映射的共享主键的 OneToOne 关系以错误的顺序保留两个实体,违反了外键约束。如何更改订单?

在从 jboss 7 实例迁移到当前 wildfly 的过程中,我的团队还必须将我们的休眠版本从 3 更新到 5.3.10。

在此过程中,我遇到了一个实体构造问题,我在其中遇到了一堵砖墙。

一般概念如下:

我有一个主实体类,它有多个“模块”作为属性,它们共享主实体类的主键。这些模块本身就是实体类,并拥有各种逻辑和进一步的关系。但是,模块实体没有任何其他持久属性。它们也没有对主要实体类的引用。

在这方面,它是(在 Java 的面向对象世界中)与共享主键的单向关系(我理解共享主键使其对数据库是双向的)。

Java 代码将是这样的:

@Entity(name = "mainEntity")
@Table(name = "main_entity")
public class MainEntity {
// Business Logic ...


@Id
  private Long id;

  @OneToOne( targetEntity = ModuleA.class, cascade = CascadeType.ALL, optional = false,
      orphanRemoval = true )
  @PrimaryKeyJoinColumn( name = "id", referencedColumnName = "id" )
private ModuleA moduleA;
// More Modules...

}

@Entity(name=moduleA)
@Table(name=module_a)
public class ModuleA {
  @Id
  private Long id;
  // other relationships to entirely different entities,
  // but no reference to mainEntity or other "modules"
}

在我们以前的系统中,这工作得很好。当使用类似的东西时

entityManager.persist(mainEntity);

模块将首先被持久化,然后是 mainEntity。

然而,在我们更新的休眠版本中,情况并非如此。使用这个映射,插入顺序被颠倒,entityManager 将首先尝试持久化 mainEntity。这会导致违反应防止表之间不一致的外键约束。

附带说明:我尝试更改

@PrimaryKeyJoinColumn(...)

进入

@MapsId(value="id")

这实际上正确地改变了持久性顺序。但是,这样做会导致休眠不再正确理解共享主键 -> 虽然由于某种原因持久化工作,

entityManager.find(ModuleA.class,primaryKey);

不起作用,产生诸如“列 mainEntity.moduleA_id 不存在”之类的错误。

有没有一种方法可以表达需要先持久化模块,就像 Hibernate 3 为我们所做的那样?

我将不胜感激任何帮助。

PS:这是我的第一个问题,如果需要更多信息,或者配方有问题,请告诉我。:)

4

1 回答 1

0

好的,经过一些分析,我想分享我们对此所做的工作。

首先,问题中提供的映射适用于 Hibernate 3.6.10.Final 直到 Hibernate 5.2.13.Final 开始失败。奇怪的是,从 5.4.0.CR1 开始,它又开始工作了。

我们还没有找到在约束到位的情况下继续使用此映射的方法。在我们的例子中,我们认为约束不值得麻烦,但是为了更可靠地映射这种事情,我们发现使用 @MapsId 更成功。在那里,模块需要对 MainEntity 的引用,并在其上使用 @MapsId 来派生其 id。

于 2020-03-06T06:19:30.463 回答