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

时间:2013-06-24 19:23:02

标签: java hibernate

我有一个包含两个表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

我该如何解决问题?

7 个答案:

答案 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)