我有一个包含两个表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
}
当我尝试保存用户对象时,我得到以下异常:
org.hibernate.HibernateException: Data was not saved: object references an unsaved transient instance - save the transient instance before flushing: com.kyrogaming.models.Country
我该如何解决问题?
答案 0 :(得分:25)
除非你告诉Hibernate这个新保存的对象所引用的所有其他对象,否则你无法将事情保存到Hibernate。所以在这种情况下,你告诉Hibernate关于User
,但没有告诉它Country
。
您可以通过两种方式解决此类问题。
手动强>
在保存session.save(country)
之前调用User
。
<强> CascadeType的强>
您可以指定Hibernate此关系应使用CascadeType传播某些操作。在这种情况下,CascadeType.PERSIST将完成这项工作,CascadeType.ALL也是如此。
引用现有国家/地区
根据您对@zerocool的回复,您有第二个问题,即当您有两个User
个具有相同Country
的对象时,您无法确定它是相同的 Country
。为此,您必须从数据库中获取相应的Country
,在新用户上设置它,然后保存User
。然后,您的两个User
对象将引用相同的Country
,而不仅仅是两个碰巧具有相同名称的Country
个实例。查看Criteria
API作为获取现有实例的一种方式。
答案 1 :(得分:12)
在您的国家/地区对象中添加的用户看起来不在数据库中。您需要使用级联来确保当国家/地区持久化时,所有不在数据中但与国家/地区相关联的用户也会被保留。
下面的代码应该有所帮助:
@ManyToOne (cascade = CascadeType.ALL)
@JoinColumn (name = "countryId")
private Country country;
答案 2 :(得分:3)
我遇到了同样的问题。在我的情况下,它出现了,因为查找表“country”具有countryId == 0和原始主键的现有记录,我尝试使用countryID == 0保存用户。将国家/地区的主键更改为Integer。现在Hibernate可以识别新记录。
有关使用包装类作为主键的建议,请参阅this stackoverflow question
答案 3 :(得分:3)
为了加上我的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
值
给出here
的相同答案答案 4 :(得分:0)
它应该是CascadeType.Merge,在这种情况下,如果记录已经存在,它将更新。
答案 5 :(得分:0)
好吧,如果你已经给出了
@ManyToOne ()
@JoinColumn (name = "countryId")
private Country country;
然后该类的对象我的意思是国家需要先保存。
因为只有当该用户的国家/地区可以使用该密钥时,它才会允许用户保存到数据库中。表示当且仅当国家/地区表中存在该国家/地区时才允许用户保存。
因此,您需要先将该国家/地区保存到表格中。
答案 6 :(得分:0)
这是因为 CASCADE TYPE
如果您愿意
@OneToOne(cascade = CascadeType.ALL)
您可以像这样保存对象
user.setCountry(country);
session.save(user)
但如果您放
@OneToOne(cascade={
CascadeType.PERSIST,
CascadeType.REFRESH,
...
})
您需要这样保存对象
user.setCountry(country);
session.save(country)
session.save(user)