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

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


评论

在想要的上下文中是这个错误吗?有无瞬变变量?

#1 楼

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

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

评论


这不是隐含的吗?您是否不总是希望Hibernate保存它们?

–马库斯·莱昂(Marcus Leon)
2010-4-12 18:27

@Marcus-不,不是。您可能需要手动处理它们。

– Bozho
10年4月12日在20:27

博zh是对的。我遇到了一些情况,这些情况是我想要手动管理集合的,这是因为它们的大小,或者是因为业务规则不允许同时保存集合中的所有对象。

– Alex Marshall
2010年11月19日,0:35

它不仅会发生在集合上,而且还会发生简单的一对一映射

–塞巴斯蒂安·洛伯(Sebastien Lorber)
2012年7月16日在9:46

从CascadeType.PERSIST开始并使用persist保存会更好吗?

–塞尔吉·谢夫奇克(Sergii Shevchyk)
2012年9月27日19:07在

#2 楼

我相信这可能只是重复的答案,但为了澄清起见,我在@OneToOne映射和@OneToMany上都得到了这个。在这两种情况下,都是我尚未添加到Child中的Parent对象尚未保存在数据库中的事实。因此,当我将Child添加到Parent中,然后保存Parent时,Hibernate在保存Parent时会扔出"object references an unsaved transient instance - save the transient instance before flushing"消息。案件。这保存了cascade = {CascadeType.ALL}Parent's

对于任何重复的回答,我们都非常抱歉,只想进一步向人们澄清。

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


评论


如果我不想在@OneToOne关系上级联保存怎么办?首次创建两个对象时,如何在不触发异常的情况下将其中一个保存到数据库?

– xtian
16年5月5日在14:30

如果我想在某些情况下而不是其他情况下保存孩子该怎么办?

– Omaruchan
16 Dec 6'在18:17

@xtian:那么,您必须通过使用EntityManager持久化对象,以正确的顺序保存到数据库。基本上,您只需要说em.persist(object1);。 em.persist(object2);等等

–kaba713
18年1月24日在15:20

我在使用@Inheritance时遇到了这个问题,在本例中为TABLE_PER_CLASS,我引用的是子类。 CascadeType.ALL修复了它。

– Jim ReesPotter
18 Mar 17 '18 at 21:08



或者,您已经使用新的MyEntity创建了实体对象(没有将其同步到数据库-刷新),而不是从数据库中获取了它的同步实例。使用该实例进行Hibernate查询会通知您,数据库中的预期内容与应用程序内存中的内容有所不同。在这种情况下,只需从DB同步/获取您的实体不稳定并使用它即可。然后不需要CascadeType.ALL。

–区
19年8月20日在12:40



#3 楼

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

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

技巧是确保设置了引用对象中的ID和VERSION,以便Hibernate认为引用对象不是需要保存的新对象。这对我有用。

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

评论


此评论使我走上了正确的道路。我正在将父级的新实例分配给其子级的属性。因此,NH认为它们是不同的实例。

– elvin
2014年5月21日,3:17

是。例如,如果不包括关联对象的ID,则会发生这种情况(例如,@ JsonIgnore忽略了该对象)。 Hibernate无法识别关联的实体,因此它想保存它。

–罗里·斯坦普(Rori Stumpf)
2014年12月31日在17:08

#4 楼

简介

正如我在使用JPA和Hibernate时在本文中所解释的,实体可以处于以下4种状态之一:



New -从未与Hibernate会话(也称为持久性上下文)相关联且未映射到任何数据库表行的新创建的对象被视为处于“新建”或“瞬态”状态。

要变得持久后,我们需要显式调用persist方法或使用可传递持久性机制。


持久性-持久性实体已与数据库表行相关联,并且由当前正在运行的持久性上下文。

(在会话刷新期间)将检测到对此类实体所做的任何更改并将其传播到数据库。

已分离-当前运行的持久性上下文关闭后,所有先前管理的实体都将分离。
已删除-尽管JPA要求只允许删除受管实体,但Hibernate也可以删除已分离的实体(但只能通过remove方法调用) )。

实体状态转换

要将实体从一种状态移动到另一种状态,可以使用persistremovemerge方法。



解决问题

您在问题中描述的问题:

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


是由以下原因引起的将处于“新建”状态的实体与处于“受管”状态的实体相关联。

将子实体与父实体中的一对多集合相关联时,可能会发生这种情况

所以,正如我在本文中所解释的,您可以通过在触发事件的实体关联中添加级联来解决此问题。 d此失败,如下所示:

cascade关联

@OneToOne(
    mappedBy = "post",
    orphanRemoval = true,
    cascade = CascadeType.ALL)
private PostDetails details;



请注意我们为@OneToOne属性添加的CascadeType.ALL值。


cascade关联同样,@OneToMany适用于双向CascadeType.ALL关联。

现在,为了使级联在双向上正常工作,您还需要确保父级和子级关联是同步的。


查阅本文,以获得有关实现此目标的最佳方法的更多详细信息。


@OneToMany关联

@OneToMany(
    mappedBy = "post", 
    orphanRemoval = true,
    cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();


@ManyToMany关联中,不能使用@ManyToManyCascadeType.ALL,因为这会将删除实体的状态转换从一个父实体传播到另一个父实体。

因此,对于orphanRemoval关联,通常可以级联@ManyToManyCascadeType.PERSIST操作。或者,您可以将其扩展为CascadeType.MERGEDETACH


有关映射REFRESH关联的最佳方法的更多详细信息,请同时阅读本文。


评论


Hibernate如何确定实例已分离?它只是在查看ID,如果它为null,则认为该实例已分离或是否涉及其他内容?

– ACV
9月3日23:17

对于合并,它将运行SELECT查询。否则,它将检查ID和版本。

– Vlad Mihalcea
9月4日下午3:46

#5 楼

或者,如果您想使用最少的“功能”(例如,如果您不想级联删除)来实现所需的功能,请使用

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

...

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


评论


这应该是公认的答案。 CascadeType.ALL ist太宽

– lilalinux
16 Sep 15'7:48

从Hibernate 5.2.8开始,似乎没有办法用JPA注释达到相同的效果。例如,@ManyToMany(cascade = {PERSIST,MERGE,REFRESH,DETACH})(除REMOVE以外的所有东西)不会像Hibernate的CascadeType.SAVE_UPDATE那样层叠更新。

– jcsahnwaldt恢复莫妮卡
17 Mar 16 '17 at 12:53

#6 楼

在我的情况下,这是由于双向关系的CascadeType一侧没有@ManyToOne引起的。更准确地说,我在CascadeType.ALL一侧有@OneToMany,而在@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;


评论


如果我这样做,然后保存父实体,那么发生的是父表中有两个行,即两个插入。我认为是因为我们在父实体和子实体上都有级联?

–程序员
2月2日,晚上8:53

#7 楼

对于我来说,这是持久存在于数据库中的现有记录的带有@Version注释的字段的值为NULL的实体(用于乐观锁定)时发生的。将数据库中的NULL值更新为0可以更正此问题。

评论


这应该是一个新问题,应该将其添加为错误,至少是具有误导性的异常。原来这是造成我问题的原因。

– BML
17年9月12日在19:08

这解决了我的问题

–贾德·查欣(Jad Chahine)
1月15日13:25



#8 楼

这不是错误的唯一原因。我刚才遇到此错误是因为我的编码出现错字错误,我相信这会设置已保存的实体的值。

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


评论


与我的问题类似。毕竟,当我在本地重新加载实体时,设置属性,然后保存,它可以正常工作。

–CsBalazs匈牙利
2014年11月26日12:43

#9 楼

除非确实需要,否则请不要使用Cascade.AllRolePermission具有双向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);


,而如果对象只是一个“新”对象,则将引发相同的错误。

评论


Cascade.All是100%正确的惰性解决方案,仅应在需要时应用。首先,如果实体已经存在,请检查是否已将其加载到当前的实体管理器中(如果尚未加载)。

–雷纳托·门德斯(Renato Mendes)
17 Mar 3 '17 at 16:43

#10 楼

如果您的收藏集可为空,请尝试:object.SetYouColection(null);

评论


这完全是我的问题。我从未想过必须手动将其设置为null。

–死神
15年4月20日在15:18

这也是我的问题。我没有使用集合,所以一开始我没有尝试过,但是我将对象设置为null,现在它可以工作了。

–饲料
16年8月25日在22:03

#11 楼

除了所有其他好的答案之外,如果您使用merge来持久化对象,并且不小心忘记在父类中使用对象的合并引用,则可能会发生这种情况。考虑下面的示例

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


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

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


#12 楼

加上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设置为新的员工实例,而实际上并没有

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

因此,请注意PK ID的null

评论


如果可以为空怎么办?

– vipin cp
18年4月18日在13:00

我有类似的问题。当我的deptID为0时,我得到了异常。任何其他大于0的值都可以使用。有趣的是我有一个id为0的部门。

–古斯塔沃
18/12/28在15:12

#13 楼

当我使用标记为@Transactional的方法创建一个新实体和一个关联实体,然后在保存之前执行查询时,这个问题发生了。 Ex

@Transactional
public someService() {
    Entity someEntity = new Entity();
    AssocaiatedEntity associatedEntity = new AssocaitedEntity();
    someEntity.setAssociatedEntity(associatedEntity);
    associatedEntity.setEntity(someEntity);

    // Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
    someDao.getSomething();

    entityDao.create(someEntity);
}


要修复,我在创建新实体之前执行了查询。

#14 楼

当我使用

getSession().save(object)


时出现此错误,但是当我使用

getSession().saveOrUpdate(object) 

时却没有问题

#15 楼

我也面临同样的情况。通过在属性上方设置以下注释,可以解决提示的异常。

我遇到的异常。

Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany


要克服,注释I

    @OneToMany(cascade = {CascadeType.ALL})
    @Column(name = "ListOfCarsDrivenByDriver")
    private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();


Hibernate引发异常的原因:

此异常在您的控制台上引发,因为我附加到父对象的子对象对象当时不在数据库中。

通过提供@OneToMany(cascade = {CascadeType.ALL}),它告诉Hibernate在保存父对象的同时将它们保存到数据库中。

#16 楼

为了完整起见,当您尝试执行以下操作时,也会出现A

org.hibernate.TransientPropertyValueException 


带有消息

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


保留/合并一个实体,并引用另一个碰巧分离的实体。

#17 楼

另一个可能的原因:在我的情况下,我试图在保存父项之前先将孩子保存在一个全新的实体上。

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


#18 楼

还有另一种可能导致此错误进入休眠状态的可能性。您可以将对象A的未保存引用设置为附加的实体B,并希望保留对象C。即使在这种情况下,也会出现上述错误。

#19 楼

如果您使用的是Spring Data JPA,则在服务实现中添加@Transactional注释将解决此问题。

#20 楼

我认为是因为您已尝试持久保存一个具有对另一个尚未持久的对象的引用的对象,因此它尝试在“ DB端”中对不存在的行进行引用

#21 楼

就我而言,问题完全不同。我有两个课程,分别是c1和c2。 C1和C2之间的依赖关系是OneToMany。现在,如果我将C1保存在DB中,则会引发上述错误。
此问题的解决方案是从使用者请求中获取第一个C2的ID,并通过存储库调用找到C2。然后将C2保存到C1对象中。 C1,一切正常。

#22 楼

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

进行一对一关系的简单检查

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


评论


相反,子实体保存FK值并取决于父实体,因此您需要先保存父实体!在代码块中,您具有正确的权限。

–Sõber
17年12月17日在17:44

#23 楼

错误的可能原因之一是父实体的值的设置不存在;例如,对于部门雇员关系,您必须编写此代码才能解决错误:

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


#24 楼

此错误有很多可能性,添加页面或编辑页面上也有其他可能性。以我为例,我试图保存一个对象AdvanceSalary。问题在于,在编辑中AdvanceSalary employee.employee_id为null,因为在编辑时未设置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;
        }

    }


#25 楼

当我不保留父对象但我正在保存孩子时,我遇到了此异常。为了解决该问题,在同一会话中,我同时保留了子对象和父对象,并在父对象上使用了CascadeType.ALL。

#26 楼

情况1:
当我尝试创建一个父对象并将该父对象的引用保存到其子对象,然后再进行其他一些DELETE / UPDATE查询(JPQL)时,遇到了此异常。因此,在创建父对象和使用相同父引用创建子对象之后,我只需flush()新创建的实体。它对我有用。

案例2:

父类

public class Reference implements Serializable {

    @Id
    @Column(precision=20, scale=0)
    private BigInteger id;

    @Temporal(TemporalType.TIMESTAMP)
    private Date modifiedOn;

    @OneToOne(mappedBy="reference")
    private ReferenceAdditionalDetails refAddDetails;
    . 
    .
    .
}


子类:

public class ReferenceAdditionalDetails implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @OneToOne
    @JoinColumn(name="reference",referencedColumnName="id")
    private Reference reference;

    private String preferedSector1;
    private String preferedSector2;
    .
    .

}


在上述情况下,当parent(Reference)和child(ReferenceAdditionalDetails)具有OneToOne关系时,当您尝试创建Reference实体,然后创建其Child(ReferenceAdditionalDetails)时,它将给您同样的例外。因此,为避免发生异常,您必须为子类设置null,然后创建父类。(示例代码)

.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.


#27 楼

我的问题与JUnit的@BeforeEach有关。即使我保存了相关实体(在我的情况下为@ManyToOne),我也遇到了相同的错误。

问题某种程度上与我父母的顺序有关。
如果我将值分配给该属性,问题就解决了。

示例。
如果我有实体Question可以具有某些类别(一个或多个),并且实体Question有一个序列: br />
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;


我必须分配值question.setId(1L);

#28 楼

只需在基类中构造映射的构造方法即可。
如果您要在实体A,实体B中建立一对一关系。
如果您将A作为基类,则A必须具有一个构造函数将B作为参数。

#29 楼

在引入乐观锁定(@Version)后,我在所有PUT HTTP事务中都面临相同的错误
在更新实体时,必须发送该实体的ID和版本。如果任何实体字段都与其他实体相关,那么我们还应该为该字段提供id和version值,否则JPA会先尝试将该相关实体作为新实体持久化
示例:我们有两个实体- ->车辆(ID,汽车,版本);汽车(编号,版本,品牌);要更新/保留“车辆”实体,请确保“车辆”实体中的“汽车”字段提供了ID和版本字段

#30 楼

在我的情况下,使用Cascade.ALL向表中添加了不必要的条目,该表已经具有相同的对象(生成没有id的子值就可以做到这一点)。
所以我必须解决从存储库中获取子对象的问题。首先,将其设置为主要对象,而不是引起问题的对象。
Student s = studentRepo.findByName(generatedObject.getStudent().getName())
generatedObject.student(s);