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

我有一个包含两个表User和Country的数据库。 我想要关系,许多用户可以属于一个县。 我使用hibernate使用以下模型类实现它:

@Entity (name = "user") public class User { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private int userId; private String username; private String password; @ManyToOne () @JoinColumn (name = "countryId") private Country country; //Getter & Setter } @Entity (name = "country") public class Country { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int countryId; private String countryName; //Getter & Setter } 

当我尝试保存用户对象时,我得到以下exception:

  org.hibernate.HibernateException: Data was not saved: object references an unsaved transient instance - save the transient instance before flushing: com.kyrogaming.models.Country 

我该如何解决这个问题?

在你告诉Hibernate关于这个新保存的对象引用的所有其他对象之前,你无法将东西保存到Hibernate。 所以在这种情况下,你告诉Hibernate一个User ,但没有告诉它有关Country

您可以通过两种方式解决此类问题。

手动

在保存User之前调用session.save(country)

CascadeType的

您可以指定Hibernate这个关系应该使用CascadeType传播一些操作。 在这种情况下,CascadeType.PERSIST将完成这项工作,CascadeType.ALL也是如此。

参考现有国家

根据您对@zerocool的响应,您还有第二个问题,即当您有两个具有相同Country User对象时,您无法确定它是否为同一个 Country 。 为此,您必须从数据库中获取相应的Country ,在新用户上设置它,然后保存User 。 然后,两个User对象将引用同一个Country ,而不仅仅是两个碰巧具有相同名称的Country实例。 查看Criteria API作为获取现有实例的一种方法。

看起来像您的Country对象中添加的用户看起来不在DB中。 您需要使用级联来确保当Country保持不变时,所有不在数据中但与Country相关联的User也会保持不变。

下面的代码应该有用:

 @ManyToOne (cascade = CascadeType.ALL) @JoinColumn (name = "countryId") private Country country; 

我有同样的问题。 在我的情况下,它出现了,因为查找表“country”具有countryId == 0和原始主键的现有记录,我尝试使用countryID == 0保存用户。 将国家/地区的主键更改为Integer。 现在Hibernate可以识别新记录。

有关使用包装类作为主键的建议,请参阅此stackoverflow问题

为了增加我的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从调用方法deptId null并且我得到相同的错误。

因此,请注意PK ID的null

这里给出的答案相同

它应该是CascadeType.Merge,在这种情况下,如果记录已经存在,它将更新。

好吧,如果你已经给了

 @ManyToOne () @JoinColumn (name = "countryId") private Country country; 

那个类的对象我的意思是国家需要先保存。

因为只有当该用户的国家/地区可以使用该密钥时,它才会允许用户保存到数据库中。 表示当且仅当该国家/地区存在于Country表中时,才允许用户保存。

因此,您需要先将该国家/地区保存到表格中。

这是因为CASCADE TYPE

如果你放

@OneToOne(级联= CascadeType.ALL)

你可以像这样保存你的对象

 user.setCountry(country); session.save(user) 

但如果你放

  @OneToOne(cascade={ CascadeType.PERSIST, CascadeType.REFRESH, ... }) 

你需要像这样保存你的对象

 user.setCountry(country); session.save(country) session.save(user)