Hibernate一对一关系:避免初始化循环与必填子对象问题
解决方案
先修正核心注解错误
原代码里Parent类同时用了@OneToOne(mappedBy = "parent")和@JoinColumn,这是矛盾的:mappedBy表示当前类是关联的被动方,主控权在Subscriber的parent属性上,所以Parent这边不能加@JoinColumn,该注解应该放在主控方Subscriber里。
让Parent初始化无需传child
给Parent的child属性加默认值null,这样初始化Parent时直接写Parent()就行,不用显式传child参数。如果不需要双向关联,甚至可以直接删掉Parent里的child属性,改成单向关联,彻底避免循环问题。
方案一:单向关联(推荐,完全符合需求)
这种方式下Parent里没有Subscriber的引用,初始化Parent完全不用管关联关系,只有Subscriber需要传入Parent,也不存在双向循环的问题。
Parent 实体类
@Entity class Parent( @Id @Column(nullable = false, updatable = false, columnDefinition = "uuid") val id: UUID = UUID.randomUUID() // 移除child属性,只保留自身字段 )
Subscriber 实体类
@Entity class Subscriber( @Id @Column(nullable = false, updatable = false, columnDefinition = "uuid") val id: UUID = UUID.randomUUID(), // 主控方,强制关联Parent,指定外键列 @OneToOne(cascade = [CascadeType.ALL], optional = false) @JoinColumn(name = "parent_id", referencedColumnName = "id") val parent: Parent )
初始化方式
// 直接初始化Parent,不用管任何关联 val parent = Parent() // 初始化Subscriber时传入Parent,完全符合你的需求 val subscriber = Subscriber(parent = parent)
方案二:双向关联(保留双向引用但解决问题)
如果确实需要双向关联,按下面的方式调整:
Parent 实体类
@Entity class Parent( @Id @Column(nullable = false, updatable = false, columnDefinition = "uuid") val id: UUID = UUID.randomUUID(), // 被动方,指定主控方属性名,加默认值null,初始化无需传入 @OneToOne(cascade = [CascadeType.ALL], mappedBy = "parent") @JsonIgnore // 序列化时忽略,避免无限循环 val subscriber: Subscriber? = null // 注意原代码类名是Subscriber,统一类名 )
Subscriber 实体类
@Entity class Subscriber( @Id @Column(nullable = false, updatable = false, columnDefinition = "uuid") val id: UUID, // 用@MapsId共享Parent的主键,无需自己生成 // 主控方,共享Parent主键,强制关联 @OneToOne(cascade = [CascadeType.ALL], optional = false) @MapsId @JoinColumn(name = "id") val parent: Parent )
初始化方式
val parent = Parent() // 初始化Subscriber时传入Parent,id直接复用Parent的id val subscriber = Subscriber(parent = parent, id = parent.id)
内容的提问来源于stack exchange,提问作者DragonKnight
相关产品推荐
相关产品推荐

