简介
使用 JPA 和 Hibernate 时,实体可以处于以下 4 种状态之一:
-
New - 从未与 Hibernate Session(又名 Persistence Context)关联且未映射到任何数据库表行的新创建对象被视为处于 New 或 Transient 状态。
要成为持久化,我们需要显式调用persist 方法或使用传递持久化机制。
-
持久性 - 持久性实体已与数据库表行相关联,并由当前运行的持久性上下文管理。
将检测到对此类实体所做的任何更改并将其传播到数据库(在会话刷新期间)。
实体状态转换
要将实体从一种状态移动到另一种状态,您可以使用persist、remove 或merge 方法。
解决问题
您在问题中描述的问题:
object references an unsaved transient instance - save the transient instance before flushing
是由于将处于 New 状态的实体与处于 Managed 状态的实体相关联。
当您将子实体与父实体中的一对多集合相关联,并且该集合没有cascade 实体状态转换时,可能会发生这种情况。
因此,您可以通过向触发此故障的实体关联添加级联来解决此问题,如下所示:
@OneToOne 关联
@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
注意我们为cascade 属性添加的CascadeType.ALL 值。
@OneToMany 关联
@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
同样,CascadeType.ALL 适用于双向 @OneToMany 关联。
现在,为了使级联在双向正常工作,您还需要确保父关联和子关联同步。
@ManyToMany 关联
@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
在@ManyToMany 关联中,您不能使用CascadeType.ALL 或orphanRemoval,因为这会将删除实体状态转换从一个父实体传播到另一个父实体。
因此,对于@ManyToMany 关联,您通常级联CascadeType.PERSIST 或CascadeType.MERGE 操作。或者,您可以将其扩展为 DETACH 或 REFRESH。