数据未保存:对象引用未保存的瞬态实例 – 在刷新之前保存瞬态实例
我有一个包含两个表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)