Hibernate单向一对一映射:PersonStatus中person字段为空或需移除
解决方案
一、实现真正的单向一对一映射(移除PersonStatus中的person字段)
当前你的配置本质是双向一对一映射,因为PersonEntity中使用了mappedBy = "person",指定关联由PersonStatusEntity的person字段维护。要实现从Person到PersonStatus的单向映射,只需调整注解配置并移除PersonStatusEntity中的person字段:
修改后的实体类代码
PersonEntity
@Entity(name = "Person") class PersonEntity( @Id @Column(name = "id", updatable = false, nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, val name: String, // 移除mappedBy,改用@JoinColumn指定外键关联 @OneToOne(cascade = [CascadeType.ALL], fetch = FetchType.EAGER) @JoinColumn( name = "person_id", referencedColumnName = "id", unique = true // 一对一映射需要唯一约束,确保一个Person对应一个PersonStatus ) var personStatus: PersonStatusEntity, )
PersonStatusEntity
@Entity(name = "PersonStatus") class PersonStatusEntity( @Id @Column(name = "id", updatable = false, nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, // 移除person字段,实现真正单向映射 @Enumerated(EnumType.STRING) val status: Status, @UpdateTimestamp val updateTime: OffsetDateTime? = null )
说明
- 将
PersonEntity作为关联的维护端,通过@JoinColumn指定person_status表中的person_id字段作为外键,关联person表的id字段。 unique = true保证一对一的约束关系,避免多个PersonStatus关联同一个Person。- 查询
Person时会自动关联加载对应的PersonStatus,且PersonStatus中不再有Person的引用,完全符合单向需求。
二、保留PersonStatus的person字段并使其不为null
如果因某些原因无法移除person字段,可通过以下两种方式确保查询时该字段不为null:
方式1:修改注解配置,强制关联加载
调整两个实体类的@OneToOne注解,指定立即加载并确保关联查询时双向加载:
PersonEntity
@Entity(name = "Person") class PersonEntity( @Id @Column(name = "id", updatable = false, nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, val name: String, @OneToOne(mappedBy = "person", cascade = [CascadeType.ALL], fetch = FetchType.EAGER) var personStatus: PersonStatusEntity, )
PersonStatusEntity
@Entity(name = "PersonStatus") class PersonStatusEntity( @Id @Column(name = "id", updatable = false, nullable = false) @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, @OneToOne(cascade = [CascadeType.ALL], fetch = FetchType.EAGER) @JoinColumn(name = "person_id", referencedColumnName = "id") var person: PersonEntity? = null, @Enumerated(EnumType.STRING) val status: Status, @UpdateTimestamp val updateTime: OffsetDateTime? = null )
方式2:在Repository查询中使用JOIN FETCH强制关联
通过自定义JPQL查询,显式关联加载personStatus和其对应的person:
自定义Repository方法
interface PersonRepository : JpaRepository<PersonEntity, Long> { @Query("SELECT p FROM Person p JOIN FETCH p.personStatus ps JOIN FETCH ps.person WHERE p.name = :name") fun findOneByName(@Param("name") name: String): PersonEntity? }
说明
- 方式1通过
fetch = FetchType.EAGER强制Hibernate在查询Person时,同时加载personStatus以及personStatus中的person引用。 - 方式2通过
JOIN FETCH显式指定关联加载,相比全局立即加载更灵活,避免不必要的性能开销。
内容的提问来源于stack exchange,提问作者Kartik
相关产品推荐
相关产品推荐

