【问题标题】:Hibernate One-to-One and Many-to-One relationship strange behaviour after saving entities保存实体后休眠一对一和多对一关系的奇怪行为
【发布时间】:2018-12-11 08:19:02
【问题描述】:

我将 Spring Boot 与 Spring Data 一起使用,而为了保存实体,我使用 CrudRepository。我有 2 个实体:Org 和 OrgDef。这个想法是为一个组织存储多个定义。 Org 是不可变的部分,而 OrgDef 是可变的。这是它在代码中的样子:

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
@Table(name = "org", uniqueConstraints = {
    @UniqueConstraint(columnNames = { "code" }, name = "uk_org_code"),
    @UniqueConstraint(columnNames = { "definition_id"}, 
    name = "uk_org_definitionId")})
public class Org {

@Id
@Column(
    name = "id",
    updatable = false,
    nullable = false
)
protected UUID id = UUID.randomUUID();

@Column(updatable = false)
protected String code;

@JoinColumn(nullable = false, foreignKey = @ForeignKey(name = "fk_org_definition_orgDef"))
@OneToOne(optional = false, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
protected OrgDef definition;

}



@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Setter
@Entity
@Table(name = "org_def")
public class OrgDef extends UuidIdEntity {

@Id
@Column(
    name = "id",
    updatable = false,
    nullable = false
)
protected UUID id = UUID.randomUUID();    

@JoinColumn(foreignKey = @ForeignKey(name = "fk_orgDef_orgId_org"), updatable = false)
@ManyToOne
protected Org org;

@JoinColumn(foreignKey = @ForeignKey(name = "fk_orgDef_parentId_org"))
@ManyToOne
protected Org parent;
}

我还想指出,Org 与 OrgDef 具有一对一的关系,而 OrgDef 与 Org 具有多对一的关系。 OrgDef 还具有“父”字段,该字段也具有多对一关系。当我保存这个类的记录时,我的表中有这个:

组织表:

OrgDef 表:

可以看到OrgDef表中的org_id字段为空,但parent_id不为空。但是,在保存时,我为 orgOrgDef 对象中的 parent 字段指定了 Org 对象。映射可能有问题?有人可以帮忙吗?因为 OrgDefparent 字段保存得很好,但 OrgDef 中的 org 字段没有保存!我的期望是 org_idparent_id 都不会为空

【问题讨论】:

  • 请分享您为保存数据而编写的代码
  • 您的 Org 与 OrgDef 关系不应该是 OneToMany 关系。我不太确定如何为一个 Org 设置多个 OrgDef。我的意思是 OrgDef 与您拥有的许多组织相关联。您使用 foreignKey 而不仅仅是 mappedBy 和 name 是否有特定原因?另外为什么不级联删除?如果没有 Org,OrgDef 有什么用?
  • @kaba713 是特殊结构)意思是我写了修改历史,这个结构很有用。是的,我知道这没有正确映射,但是这个映射解决了我的业务逻辑
  • 在这种情况下,您的实体应该仍然具有 OneToMany 关系,并且您的业务逻辑应该只提供最新的 OrgDef,前提是您的 Org 应该这样做。您不应该仅仅依靠映射来获得正确的修改历史。除此之外,Hibernate 确实有一种方法可以为您记录元素,它被称为 Envers:hibernate.org/orm/envers
  • @kaba713 是的,Org 实体与 OrgDef 具有一对一的关系,并且在任何修改中,我都将最新版本的 OrgDef 设置为 Org。

标签: java hibernate spring-boot spring-data-jpa spring-data


【解决方案1】:

我发现了问题,我在 OrgDef 类的 org 字段上使用了这个注解:

@JoinColumn(foreignKey = @ForeignKey(name = "fk_orgDef_orgId_org"), updatable = false)

我指定这个字段是不可更新的,所以hibernate不能向这个字段插入值。我从此注释中删除了updatable = false,现在一切正常!

【讨论】:

  • 这很好用,但我建议在 JoinColumn 注释中使用列名,以便在代码中清晰(对于其他开发人员)。
  • 我不明白所有这些关系。但是,它对我来说仍然很奇怪。一对一意味着两个实体共享相同的主键值。这似乎不是这里的情况。小心外键。仅使用少量测试记录时,它可能看起来是正确的。
  • @StefanSteinegger 这种映射的原因是将实体的定义存储在单独的实体中,我们可以存储修改历史。例如,我有 Person 和 PersonDef。 PersonDef 将有姓名、姓氏、电话、地址等。 Person 将只有唯一的 Id 和对 PersonDef 的引用(一对一),但如果我想重命名我的人并更新名称字段,我将创建新的记录在 PersonDef 表中。通过这个操作,我可以存储 midifications 的历史,并且 Person 类将具有 PersonDef 的最新版本。这个映射解决了我的业务逻辑。
  • 好的,我知道这种模式。我实现的完全相同。这绝对不是一对一的关系,因为许多 Defs 指向同一个 Person。由于一对一是主键关系,因此无法更改。当它应该是历史上最新意义上的“当前有效的def”或“最新的def”时,所以每当您添加新的def时它都会改变。
猜你喜欢
  • 1970-01-01
  • 2015-04-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-11
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
相关资源
最近更新 更多