簡體   English   中英

數據未保存:對象引用未保存的瞬態實例 - 在刷新之前保存瞬態實例

[英]Data was not saved: object references an unsaved transient instance - save the transient instance before flushing

我有一個包含兩個表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

我該如何解決這個問題?

在你告訴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中。 您需要使用級聯來確保當國家/地區持久化時,所有不在數據中但與國家/地區相關聯的用戶也會被保留。

下面的代碼應該有幫助

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

為了增加我的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

這里給出的答案相同

我有同樣的問題。 在我的情況下,它出現了,因為查找表“country”具有countryId == 0和原始主鍵的現有記錄,我嘗試使用countryID == 0保存用戶。 將國家/地區的主鍵更改為Integer。 現在Hibernate可以識別新記錄。

有關使用包裝類作為主鍵的建議,請參閱此stackoverflow問題

它應該是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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM