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

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

当前回答

错误的一个可能原因是父实体的值设置不存在;例如,对于部门员工关系,为了修复错误,您必须编写以下内容:

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);

其他回答

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

我遇到了这个问题,不想保存对引用对象的更改,所以我希望级联类型为NONE。

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

查看要保存的类中的所有关系,以计算关联对象(以及关联对象的关联对象),并确保在对象树的所有对象中设置了ID和VERSION。

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

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

介绍

使用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。

此错误的可能性非常多,其他一些可能性也出现在添加页或编辑页上。在我的案例中,我试图保存一个对象AdvanceSalary。问题是,在编辑AdvanceSalary employee.employee_id时为空,因为在编辑时我没有设置employee。

    @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;
        }

    }

再加上我的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的空值