Hibernate一对多关联中子对象无法保存的问题咨询
1. CascadeType.PERSIST的触发场景限制
JPA的CascadeType.PERSIST仅在父对象从瞬时(Transient)状态转为持久(Persistent)状态时(比如调用session.persist(parent)保存新创建的父对象),才会级联持久化关联的子对象。而你代码中的Person是从数据库查询出来的,本身已经处于托管(Persistent)状态,全程没有对父对象执行persist操作,因此不会触发PERSIST级联。
2. 普通Java集合无法被Hibernate跟踪
你的Person类中items字段初始为null,调用saveItem时才创建普通的ArrayList。这种普通集合不属于Hibernate托管的集合(如PersistentList),Hibernate无法自动跟踪集合的元素添加操作,因此在事务提交时不会检测到新添加的Item。
方案1:精准配置级联+初始化托管集合
步骤1:初始化集合为空列表
在Person的无参构造方法中提前初始化items为ArrayList,让Hibernate能将其包装为托管集合,以便跟踪后续的元素变化:
public Person() { this.items = new ArrayList<>(); }
步骤2:补充级联类型为PERSIST + MERGE
修改@OneToMany注解的级联配置,添加CascadeType.MERGE。当父对象处于Persistent状态时,事务提交时的脏检查会触发级联merge操作,从而自动持久化新添加的Item:
@OneToMany(mappedBy = "owner", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) private List<Item> items;
方案2:手动持久化子对象(无需修改级联)
如果你不想调整级联配置,可以在添加Item后手动调用session.persist(item)。由于Item已经关联了处于Persistent状态的Person,Hibernate会自动维护外键关系:
Person person = session.get(Person.class, 13); Item item = new Item("Test item"); person.saveItem(item); session.persist(item); // 手动触发子对象持久化
CascadeType.ALL包含了MERGE级联类型,事务提交时Hibernate会对Persistent状态的Person执行merge操作,级联处理关联的Item,从而触发INSERT语句。但正如你所说,ALL会包含不必要的级联类型(如REMOVE),因此推荐使用更精准的PERSIST + MERGE组合。
内容的提问来源于stack exchange,提问作者CodeCrafter

