使用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
当前回答
这不是错误的唯一原因。我刚才遇到了它,因为我的代码中有一个错别字,我相信它设置了一个已经保存的实体的值。
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
我通过准确查找导致错误的变量(在本例中为Stringxid)发现了错误。我在保存实体并打印痕迹的整个代码块周围使用了捕获。
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
其他回答
当您具有OneToMany关系并且尝试将子实体添加到父实体中的列表中,然后通过父实体检索此列表(在保存此父实体之前),而不保存子实体本身时,也可能发生这种情况,例如:
Child childEntity = new Child();
parentEntity.addChild(childEntity);
parentEntity.getChildren(); // I needed the retrieval for logging, but one may need it for other reasons.
parentRepository.save(parentEntity);
保存父实体时引发了错误。如果我删除了前一行中的检索,则不会抛出错误,但当然这不是解决方案。
解决方案是保存子实体并将保存的子实体添加到父实体,如下所示:
Child childEntity = new Child();
Child savedChildEntity = childRepository.save(childEntity);
parentEntity.addChild(savedChildEntity);
parentEntity.getChildren();
parentRepository.save(parentEntity);
您应该在集合映射中包含cascade=“all”(如果使用xml)或cascade=CascadeType.all(如果使用注释)。
发生这种情况是因为实体中有一个集合,而该集合中有一项或多项不在数据库中。通过指定上述选项,您可以告诉hibernate在保存父对象时将其保存到数据库中。
在我的例子中,这是由于双向关系的@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;
我认为这是因为您试图持久化一个对象,该对象具有对另一个尚未持久化的对象的引用,因此它尝试在“DB端”放置对不存在的行的引用
另一个可能的原因是:在我的案例中,我试图在一个全新的实体上,先救孩子,再救父母。
User.java模型中的代码如下:
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
setNewPassword()方法创建PasswordHistory记录,并将其添加到User中的历史记录集合中。由于尚未为父级执行create()语句,因此它试图保存到尚未创建的实体集合中。我所要做的就是在调用create()之后移动setNewPassword()调用。
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);