Hibernate @OneToMany关联外键未保存问题求助
看起来你遇到的核心问题是ApiResourceEntity和PermissionScopeEntity之间的双向关联配置错误,导致保存时子表的外键没有被正确设置,同时你误解了循环引用的触发场景。让我们一步步拆解解决:
1. 修正@OneToMany的mappedBy属性
你的ApiResourceEntity中@OneToMany的mappedBy值写错了:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "intCode") private List<PermissionScopeEntity> colOauth2PermissionsScope = new ArrayList<>();
mappedBy应该指向子实体(PermissionScopeEntity)中用来关联父实体的@ManyToOne字段名称,而不是父实体的主键字段名intCode。
你需要先在PermissionScopeEntity中添加正确的@ManyToOne关联字段:
@Entity @Table(name = "tbl_permissionsscope") public class PermissionScopeEntity { // 其他字段省略... // 添加这个关联字段,名称可以自定义,比如objApiResource @ManyToOne @JoinColumn(name = "intApiCode") // 这里对应tbl_permissionsscope中关联tbl_apiresources.intCode的外键列名 private ApiResourceEntity objApiResource; // 别忘了添加getter和setter方法 }
然后修正ApiResourceEntity中的@OneToMany配置:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "objApiResource") private List<PermissionScopeEntity> colOauth2PermissionsScope = new ArrayList<>();
2. 为什么ApplicationEntity的关联能正常工作?
你的ApplicationEntity中@OneToMany(mappedBy = "strApplication")能正常生效,是因为对应的ApplicationRoleEntity中肯定存在一个名为strApplication的@ManyToOne字段,JPA能正确识别这种双向关联关系,自动为子表设置外键。而Api这边的mappedBy指向了错误的字段,导致JPA无法关联子实体,自然不会设置外键值。
3. 关于“添加@ManyToOne触发循环引用异常”的误解
你提到的循环引用异常,大概率是**序列化(比如返回JSON接口时)**导致的,而非JPA本身的问题。JPA完全支持双向关联,解决序列化循环引用的常用方法有:
- 在其中一方的关联字段上添加
@JsonIgnore(如果使用Jackson序列化),忽略该字段的序列化 - 使用
@JsonManagedReference和@JsonBackReference标记双向关联的父/子端,明确序列化层级 - 引入DTO层,将实体转换为数据传输对象后再返回,避免直接序列化实体类
4. 保存时的关键操作:维护双向关联的两端
在保存数据时,需要手动维护双向关联的两端(这是JPA双向关联的常规要求):
比如当你给ApiResourceEntity添加PermissionScopeEntity时,要同时设置子实体的父关联:
ApiResourceEntity api = new ApiResourceEntity(); PermissionScopeEntity scope = new PermissionScopeEntity(); // 维护双向关联,这一步是关键 api.getColOauth2PermissionsScope().add(scope); scope.setObjApiResource(api); // 最后保存ApplicationEntity即可,CascadeType.ALL会级联保存所有关联实体 applicationEntity.setObjApi(api); applicationRepository.save(applicationEntity);
这样修改后,tbl_permissionsscope中的外键列(比如intApiCode)就会被正确设置为对应的tbl_apiresources.intCode值,不会再出现子表数据保存但外键为空的情况。
内容的提问来源于stack exchange,提问作者delucaezequiel

