对象引用未保存的瞬态实例 – 在刷新之前保存瞬态实例

我使用Hibernate保存对象时收到以下错误

object references an unsaved transient instance - save the transient instance before flushing 

您应该在集合映射中包含cascade="all" (如果使用xml)或cascade=CascadeType.ALL (如果使用注释)。

发生这种情况是因为您的实体中有一个集合,并且该集合中有一个或多个项目不在数据库中。 通过指定上述选项,您可以告诉hibernate在保存它们的父级时将它们保存到数据库中。

我相信这可能只是重复的答案,但只是为了澄清,我得到了@OneToOne映射以及@OneToMany 。 在这两种情况下,事实上,我添加到ParentChild对象并没有保存在数据库中。 所以当我将Child添加到Parent ,然后保存了Parent ,当保存Parent ,Hibernate会抛弃"object references an unsaved transient instance - save the transient instance before flushing"消息。

Parent's引用Child cascade = {CascadeType.ALL}添加cascade = {CascadeType.ALL}解决了这两种情况下的问题。 这救了ChildParent

对不起,任何重复的答案,只是想进一步澄清为乡亲。

 @OneToOne(cascade = {CascadeType.ALL}) @JoinColumn(name = "performancelog_id") public PerformanceLog getPerformanceLog() { return performanceLog; } 

当Hibernate认为需要保存与保存的对象相关的对象时,保存对象时会发生这种情况。

我有这个问题,不想保存对引用对象的更改,所以我想级联types为NONE。

诀窍是确保引用对象中的ID和VERSION被设置,以便Hibernate不会认为引用的对象是需要保存的新对象。 这对我有效。

仔细检查保存的类中的所有关系,以确定关联对象(以及关联对象的关联对象),并确保在对象树的所有对象中都设置了ID和VERSION。

或者,如果你想使用最小的“权力”(例如,如果你不想级联删除)来实现你想要的,使用

 import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; ... @Cascade({CascadeType.SAVE_UPDATE}) private Set<Child> children; 

这发生在持久化数据库中的现有logging具有用@Version注释的字段的NULL值(用于乐观locking)的实体时。 在数据库中将NULL值更新为0已将其更正。

这不是错误的唯一原因。 我刚刚在编码中遇到了一个错字,我相信这个错误会设置一个已经保存的实体的值。

 X x2 = new X(); x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier Y.setX(x2); 

我发现确切地find哪个variables导致错误(在这种情况下String xid )的错误。 我在整个保存实体的代码块周围使用了一个接口,并打印了这些痕迹。

 { code block that performed the operation } catch (Exception e) { e.printStackTrace(); // put a break-point here and inspect the 'e' return ERROR; } 

在我的情况下,这是由于在双向关系的@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; 

如果你的集合是可空的,只需尝试: object.SetYouColection(null);

为了增加我的2美分,当我不小心发送null作为ID时,我得到了同样的问题。 下面的代码描述了我的场景(和OP没有提到任何特定的场景)

 Employee emp = new Employee(); emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown // calls to other setters... em.persist(emp); 

在这里,我将现有的部门ID设置为一个新的员工实例,而实际上并没有首先获取部门实体,因为我不想另外select查询来触发。

在某些情况下, deptId PKID来自调用方法为null ,我得到相同的错误。

所以,注意PK ID的null

我得到这个错误,当我使用

 getSession().save(object) 

但使用时没有问题

 getSession().saveOrUpdate(object) 

除了所有其他的好的答案之外,如果你使用merge来保存一个对象,并且不小心忘记在父类中使用对象的合并引用,就会发生这种情况。 考虑下面的例子

 merge(A); B.setA(A); persist(B); 

在这种情况下,您合并A但忘记使用A合并对象。 要解决这个问题,你必须像这样重写代码。

 A=merge(A);//difference is here B.setA(A); persist(B); 

另外一个可能的原因是:就我而言,我试图在拯救父母之前,把这个孩子拯救在一个全新的实体上。

这个代码在User.java模型中是这样的:

 this.lastName = lastName; this.isAdmin = isAdmin; this.accountStatus = "Active"; this.setNewPassword(password); this.timeJoin = new Date(); create(); 

setNewPassword()方法创build一个PasswordHistorylogging,并将其添加到User中的历史logging集合中。 由于create()语句还没有被父执行,所以它试图保存到尚未创build的实体的集合中。 我所需要做的就是在调用create()之后移动setNewPassword()调用。

 this.lastName = lastName; this.isAdmin = isAdmin; this.accountStatus = "Active"; this.timeJoin = new Date(); create(); this.setNewPassword(password); 

解决这个问题的简单方法是保存这两个实体。 首先保存子实体,然后保存父实体。 因为父实体依赖于子实体的外键值。

简单的一对一关系考试

 insert into Department (name, numOfemp, Depno) values (?, ?, ?) Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?) Session session=sf.openSession(); session.beginTransaction(); session.save(dep); session.save(emp); 

还有另一种可能性,可能会导致在hibernate这个错误。 您可以将对象A的未保存的引用设置为附加的实体B并且希望保留对象C 即使在这种情况下,你也会得到上述的错误。

不要使用Cascade.All直到你真的必须。 RolePermission有双向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); 

而如果对象只是一个“新”的,那么它会抛出同样的错误。

造成这种错误的一个可能原因是没有设定母体实体的价值。 例如对于一个部门 – 雇员关系,你必须写这个以解决这个错误:

 Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with @RequestParam String department employee.setDepartment(dept); 

有这么多的可能性,这个错误还有一些其他的可能性也是添加页面或编辑页面。 在我的情况下,我试图挽救一个对象AdvanceSalary。 问题是,在编辑AdvanceSalary employee.employee_id为空因为在编辑我没有设置employee.employee_id。 我做了一个隐藏的领域,并设置它。 我的代码工作得很好。

  @Entity(name = "ic_advance_salary") @Table(name = "ic_advance_salary") public class AdvanceSalary extends BaseDO{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "employee_id", nullable = false) private Employee employee; @Column(name = "employee_id", insertable=false, updatable=false) @NotNull(message="Please enter employee Id") private Long employee_id; @Column(name = "advance_date") @DateTimeFormat(pattern = "dd-MMM-yyyy") @NotNull(message="Please enter advance date") private Date advance_date; @Column(name = "amount") @NotNull(message="Please enter Paid Amount") private Double amount; @Column(name = "cheque_date") @DateTimeFormat(pattern = "dd-MMM-yyyy") private Date cheque_date; @Column(name = "cheque_no") private String cheque_no; @Column(name = "remarks") private String remarks; public AdvanceSalary() { } public AdvanceSalary(Integer advance_salary_id) { this.id = advance_salary_id; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } public Long getEmployee_id() { return employee_id; } public void setEmployee_id(Long employee_id) { this.employee_id = employee_id; } }