我使用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
cascade="all"
(如果使用xml)或cascade=CascadeType.ALL
(如果使用注释)。我认为这可能只是重复的答案,但是为了澄清,无论是在@OneToOne
映射还是在@OneToMany
映射中,问题都在于我要添加到Parent
的Child
对象还没有保存在数据库中。因此,当我将Child
添加到Parent
中,然后保存Parent
时,Hibernate会抛出"object references an unsaved transient instance - save the transient instance before flushing"
消息。
在Parent
对Child
的引用上添加cascade = {CascadeType.ALL}
可以解决这两种情况下的问题。这将保存Child
和Parent
。
很抱歉如果有重复的答案,只是想进一步为大家澄清。
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
创建了实体对象(没有将其与数据库同步 - 刷新),而不是从数据库中获取它的同步实例。使用该实例进行 Hibernate 查询会告诉你,你期望在数据库中的内容与你在应用程序内存中拥有的内容不同。在这种情况下 - 只需从数据库同步/获取你的实体实例并使用它即可。然后就不需要使用 CascadeType.ALL。 - Zon使用JPA和Hibernate时,实体可以处于以下4种状态之一:
要进行持久化,我们需要显式调用persist
方法或利用传递性持久性机制。
对此类实体所做的任何更改都将被检测并传播到数据库(在Session刷新时间内)。
分离 - 当前运行的Persistence Context关闭后,所有先前管理的实体都变为分离状态。后续更改将不再被跟踪,也不会发生自动数据库同步。
删除 - 虽然JPA要求只允许删除受管理的实体,但Hibernate也可以删除分离的实体(但仅通过remove
方法调用)。
要将实体从一种状态转移到另一种状态,可以使用persist
、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;
请注意我们为
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
。
merge
来 persist
一个对象是一个不好的想法。仅仅因为它偶然能够工作,并不意味着这是正确的方式。 - Vlad Mihalcea当Hibernate认为需要保存与正在保存的对象相关联的对象时,会出现此问题。
我遇到了这个问题,不想保存对相关对象所做的更改,因此希望级联类型为NONE。
诀窍是确保设置了引用对象中的ID和版本,以便Hibernate不认为引用对象是需要保存的新对象。这对我很有用。
查看您要保存的类中的所有关系,以确定相关对象(以及相关对象的相关对象),并确保在对象树中的所有对象中设置了ID和VERSION。
@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;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(除了REMOVE之外的所有操作)无法像Hibernate的CascadeType.SAVE_UPDATE
那样级联更新。 - jcsahnwaldt Reinstate Monica在我持久化一个实体时,发生了这种情况,数据库中现有记录对于使用@Version(用于乐观锁定)注释的字段具有NULL值。在数据库中将NULL值更新为0后,问题得到了纠正。
这不是错误的唯一原因。我刚刚在我的代码中发现了一个打字错误,我相信这个错误设置了一个已经保存的实体的值。
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
我通过找到导致错误的变量(在这种情况下为String xid
)来发现了错误。我使用了一个catch
包围代码块保存实体并打印跟踪信息。
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
除非确实需要,否则不要使用 Cascade.All
。 Role
和 Permission
之间存在双向的manyToMany
关系。那么以下代码将会正常工作。
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
如果对象只是一个“新”对象,那么它会抛出相同的错误。
除了其他好的答案,如果您使用merge
来持久化一个对象并意外忘记在父类中使用合并引用,则可能会发生这种情况。请考虑以下示例:
merge(A);
B.setA(A);
persist(B);
A
,但忘记使用合并后的A
对象。为了解决问题,您必须像这样重写代码。A=merge(A);//difference is here
B.setA(A);
persist(B);