使用Hibernate保存对象时收到以下错误
object references an unsaved transient instance - save the transient instance before flushing
使用Hibernate保存对象时收到以下错误
object references an unsaved transient instance - save the transient instance before flushing
当前回答
介绍
使用JPA和Hibernate时,实体可以处于以下4种状态之一:
新建-新创建的对象从未与Hibernate会话(也称为持久性上下文)关联,且未映射到任何数据库表行,则被视为处于新建或临时状态。
为了持久化,我们需要显式调用持久化方法或使用传递持久化机制。
持久性-持久性实体已与数据库表行关联,并由当前运行的持久性上下文管理。
对此类实体所做的任何更改都将被检测并传播到数据库(在会话刷新时间内)。
分离-一旦当前运行的Persistence Context关闭,所有以前管理的实体都将分离。将不再跟踪连续的更改,并且不会发生自动数据库同步。移除-虽然JPA要求只允许移除托管实体,但Hibernate也可以删除分离的实体(但只能通过移除方法调用)。
实体状态转换
要将实体从一个状态移动到另一个状态,可以使用persistent、remove或merge方法。
解决问题
您在问题中描述的问题:
object references an unsaved transient instance - save the transient instance before flushing
是通过将状态为“新建”的实体与状态为“托管”的实体关联而导致的。
当您将子实体关联到父实体中的一对多集合,并且集合不级联实体状态转换时,可能会发生这种情况。
因此,您可以通过向触发此故障的实体关联添加级联来解决此问题,如下所示:
@OneToOne协会
@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
请注意我们为级联属性添加的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或orphanRemove,因为这会将删除实体状态转换从一个父实体传播到另一个父图元。
因此,对于@ManyToMany关联,通常级联CascadeType.PERSIST或CascadeType.MERGE操作。或者,可以将其扩展到DETACH或REFRESH。
其他回答
当Hibernate认为需要保存与正在保存的对象关联的对象时,在保存对象时会发生这种情况。
我遇到了这个问题,不想保存对引用对象的更改,所以我希望级联类型为NONE。
诀窍是确保设置了被引用对象中的ID和VERSION,这样Hibernate就不会认为被引用对象是需要保存的新对象。这对我有用。
查看要保存的类中的所有关系,以计算关联对象(以及关联对象的关联对象),并确保在对象树的所有对象中设置了ID和VERSION。
当我没有持久化父对象但我正在保存孩子时,我遇到了这个异常。为了解决这个问题,在同一个会话中,我保留了子对象和父对象,并在父对象上使用了CascadeType.ALL。
如果您的集合可以为null,请尝试:object.SetYouColaction(null);
在我的例子中,这是由于双向关系的@ManyToOne一侧没有CascadeType导致的。更准确地说,我在@OneToMany端有CascadeType.ALL,而在@ManyToOne端没有。将CascadeType.ALL添加到@ManyToOne解决了该问题。一对多:
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
多对一(导致问题)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
多对一(通过添加CascadeType.PERSIST修复)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
或者,如果你想使用最小的“权力”(例如,如果你不想级联删除)来实现你想要的,使用
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;