三个共享主键实体的Hibernate @OneToOne映射配置问题
解决Hibernate共享主键的OneToOne关联问题
看起来你的问题出在GlobalRating实体的主键生成配置上,以及单向关联的映射细节。让我们一步步修正:
问题根源
你当前的GlobalRating实体中,主键生成器的foreign策略参数指向了globalRating——这是它自己的ID字段,Hibernate无法通过这个字段获取有效的主键值,自然无法和Provider建立正确的共享主键关联。另外,单向@OneToOne共享主键时,被关联方(GlobalRating)需要持有对拥有方(Provider)的引用,供主键生成器使用。
修正后的实体配置
1. 修正GlobalRating实体
@Entity @Table(name="global_rating") @Getter @Setter public class GlobalRating implements Serializable{ private static final long serialVersionUID = 1L; @Id @Column(name="pk_provider$global_rating") @GeneratedValue(generator="provider_fk_generator") @GenericGenerator( name="provider_fk_generator", strategy="foreign", parameters=@Parameter(name="property", value="provider") ) private int globalRatingId; // 添加与Provider的关联,供主键生成器依赖 @OneToOne(fetch = FetchType.LAZY) @PrimaryKeyJoinColumn private Provider provider; }
2. 确认Provider实体的关联配置
你的Provider实体配置基本正确,只需确保GlobalRating的关联设置了正确的级联和可选性:
@Entity @Table(name="provider") @Getter @Setter @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "providerId") public class Provider implements Serializable, Comparable<Provider>{ private static final long serialVersionUID = 1L; @Id @Column(name="pk_account$provider") @GeneratedValue(generator="native") @GenericGenerator( name="native", strategy="foreign", parameters=@Parameter(name="property", value="account") ) private int providerId; @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @PrimaryKeyJoinColumn private Account account; // 这里保持原有配置即可,因为Provider是单向关联的拥有方 @OneToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL, optional = false) @PrimaryKeyJoinColumn private GlobalRating globalRating; }
3. 实体创建与保存的正确顺序
在保存对象时,需要确保关联关系完整建立,这样Hibernate才能正确生成共享主键:
// 1. 创建Account实例 Account account = new Account(); // 设置Account的其他属性... // 2. 创建GlobalRating实例 GlobalRating globalRating = new GlobalRating(); // 设置GlobalRating的其他属性... // 3. 创建Provider实例并关联所有对象 Provider provider = new Provider(); provider.setAccount(account); provider.setGlobalRating(globalRating); globalRating.setProvider(provider); // 关键:给GlobalRating关联对应的Provider account.setProvider(provider); // 4. 保存Account,级联保存Provider和GlobalRating entityManager.persist(account);
关键说明
foreign主键生成器必须指向一个存在的实体属性,而不是当前实体的ID字段,这样Hibernate才能从关联实体中获取主键值。- 共享主键的
@OneToOne关联中,被关联方(GlobalRating)需要持有对拥有方(Provider)的引用,这是Hibernate维护主键一致性的必要条件。 - 利用
CascadeType.ALL可以让保存Account的操作自动级联到Provider和GlobalRating,避免手动逐个保存。
内容的提问来源于stack exchange,提问作者AlejoDev
相关产品推荐
相关产品推荐

