2010-02-20 63 views

回答

528

對象應該包括cascade="all"(如果使用XML)或cascade=CascadeType.ALL(如果使用註釋)在你的收藏映射上。

發生這種情況是因爲您的實體中有一個集合,並且該集合中有一個或多個項目不存在於數據庫中。通過指定上述選項,您可以告訴hibernate在保存它們的父級時將它們保存到數據庫。

+5

這不是隱含的嗎?你不會總是希望Hibernate保存它們嗎? – 2010-04-12 18:27:42

+15

@馬庫斯 - 不,事實並非如此。你可能想要手動處理它們。 – Bozho 2010-04-12 20:27:30

+3

Bozho是對的。我遇到過我想要手動管理的集合,因爲它們的大小,或者因爲業務規則不允許同時保存集合中的所有對象。 – 2010-11-19 00:35:05

9

這不是錯誤的唯一原因。我剛剛在我的編碼中遇到了一個錯字,我相信它會設置一個已經保存的實體的值。

X x2 = new X(); 
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier 
Y.setX(x2); 

我恰好找到發現錯誤哪個變量造成的錯誤(在這種情況下String xid)。我在整個代碼塊周圍使用了一個catch,這些代碼保存了實體並打印了這些痕跡。

{ 
    code block that performed the operation 
} catch (Exception e) { 
    e.printStackTrace(); // put a break-point here and inspect the 'e' 
    return ERROR; 
} 
+0

與我的問題類似。最後,當我在本地重新加載實體時,設置屬性,然後保存,它工作正常。 – CsBalazsHungary 2014-11-26 12:43:27

153

我相信這可能只是重複的答案,但我只想澄清,我得到這個在@OneToOne映射以及一個@OneToMany。在這兩種情況下,事實上,我添加到ParentChild對象尚未保存在數據庫中。因此,當我將Child添加到Parent,然後保存Parent時,Hibernate在保存父節點時會丟棄"object references an unsaved transient instance - save the transient instance before flushing"消息。

cascade = {CascadeType.ALL}上加上Parent's參考Child解決了這兩種情況下的問題。這節省了ChildParent

對不起,任何重複的答案,只是想進一步澄清爲人。

@OneToOne(cascade = {CascadeType.ALL}) 
@JoinColumn(name = "performancelog_id") 
public PerformanceLog getPerformanceLog() { 
    return performanceLog; 
} 
+2

如果我不想在@OneToOne關係中級聯保存,該怎麼辦?當第一次創建兩個對象時,如何保存到數據庫而不觸發異常? – xtian 2016-06-05 14:30:47

+0

如果我想爲某些情況而不是某些其他人保存孩子,該怎麼辦? – Omaruchan 2016-12-06 18:17:49

+0

@xtian:那麼你必須通過使用EntityManager持久保存對象來保存正確的保存順序。基本上你只是說em.persist(object1); em.persist(Object2的);等等。 – kaba713 2018-01-24 15:20:52

18

或者,如果你想用最少的「權力」(例如,如果你不想級聯刪除),以達到你想要什麼,用

import org.hibernate.annotations.Cascade; 
import org.hibernate.annotations.CascadeType; 

... 

@Cascade({CascadeType.SAVE_UPDATE}) 
private Set<Child> children; 
+5

這應該是被接受的答案。 CascadeType.ALL太寬泛 – lilalinux 2016-09-15 07:48:12

+0

從Hibernate 5.2.8開始,似乎無法通過JPA批註實現相同的效果。例如,'@ManyToMany(cascade = {PERSIST,MERGE,REFRESH,DETACH})'(除REMOVE之外的所有)不會像Hibernate的'CascadeType.SAVE_UPDATE'那樣級聯更新。 – 2017-03-16 12:53:43

37

保存對象時,會出現這種情況當Hibernate認爲它需要保存一個與正在保存的對象相關聯的對象時。

我有這個問題,並不想保存對引用對象的更改,所以我想級聯類型爲NONE。

訣竅是確保引用對象中的ID和VERSION被設置,以便Hibernate不會認爲引用的對象是需要保存的新對象。這對我有效。

查看要保存的類中的所有關係以計算關聯對象(以及關聯對象的關聯對象),並確保在對象樹的所有對象中都設置了ID和VERSION。

+2

此評論讓我走上正軌。我將父項的一個新實例分配給其子項的屬性。所以NH認爲他們是不同的例子。 – elvin 2014-05-21 03:17:34

+0

是的。例如,如果沒有包含關聯對象的id(例如,它被@JsonIgnore忽略),就會發生這種情況。 Hibernate無法識別關聯的實體,所以它想保存它。 – 2014-12-31 17:08:14

+2

版本在數據庫中爲空,謝謝!!!!! – kwisatz 2015-09-10 15:24:17

11

對於我來說,當持久化一個實體時,在該實體中數據庫中的現有記錄對於使用@Version註釋的字段具有NULL值(用於樂觀鎖定)。將數據庫中的NULL值更新爲0可以糾正此問題。

+0

謝謝你!這是我遇到的問題。 – 2015-12-03 01:00:28

+0

這應該是一個新問題,它應該被添加爲一個錯誤,至少是誤導性的例外。這原來是我的問題的原因。 – BML 2017-09-12 19:08:13

5

如果您收藏爲空只是嘗試:object.SetYouColection(null);

+0

這完全是我的問題。我從來不會猜到我必須手動將其設置爲空。 – Deadron 2015-04-20 15:18:48

+0

這也是我的問題。我沒有使用集合,所以我一開始沒有嘗試這個,但是我把我的對象設置爲null,現在它可以工作。 – Fodder 2016-08-25 22:03:35

12

在我的情況下,它是通過在雙向關係的@ManyToOne側沒有CascadeType造成的。更確切地說,我在@OneToMany一側有CascadeType.ALL,在@ManyToOne沒有。將CascadeType.ALL添加到@ManyToOne解決了問題。 一一對多側:

@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true) 
private Set<GlobalConfigScope>gcScopeSet; 

多對一一側(導致問題)

@ManyToOne 
@JoinColumn(name="global_config_id") 
private GlobalConfig globalConfig; 

多對一一個(通過添加CascadeType.PERSIST固定)

@ManyToOne(cascade = CascadeType.PERSIST) 
@JoinColumn(name="global_config_id") 
private GlobalConfig globalConfig; 
2

我得到這個錯誤,當我使用

getSession().save(object) 

,但它沒有問題的作品,當我使用其他

getSession().saveOrUpdate(object) 
1

一個可能的原因是:在我的情況,我試圖拯救父母,一個全新的實體之前救孩子。

的代碼是這樣的一個User.java模型:

this.lastName = lastName; 
this.isAdmin = isAdmin; 
this.accountStatus = "Active"; 
this.setNewPassword(password); 
this.timeJoin = new Date(); 
create(); 

的setNewPassword()方法創建一個PasswordHistory記錄,並將其添加到歷史收集用戶。由於create()語句還沒有被父執行,所以它試圖保存到尚未創建的實體的集合中。我需要做的就是在調用create()之後移動setNewPassword()調用。

this.lastName = lastName; 
this.isAdmin = isAdmin; 
this.accountStatus = "Active"; 
this.timeJoin = new Date(); 
create(); 
this.setNewPassword(password); 
3

要添加我的2美分,我得到了同樣的問題,當我米意外發送null,作爲標識。下面的代碼描述了我的場景(並且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); 

這裏I m所現有的部門ID設置爲一個新員工的實例,而不首先獲得該部門實體,因爲我不希望另一個選擇查詢開火。

在某些情況下,deptId PKID將作爲null來自調用方法,我會得到相同的錯誤。

所以,觀看null值PK ID解決這一問題的

0

簡單的方法就是保存兩個實體。 先保存子實體,然後保存父實體。 因爲父實體依賴於子實體的外鍵值。

下面一個簡單的考試,一個關係

insert into Department (name, numOfemp, Depno) values (?, ?, ?) 
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?) 

Session session=sf.openSession(); 
     session.beginTransaction(); 
     session.save(dep); 
     session.save(emp); 
+0

這是對子實體擁有FK值並取決於父項,因此您需要先保存父項!在代碼塊中你是對的。 – 2017-12-17 17:44:25

2

所有其他好的答案旁邊,如果你使用merge堅持一個對象時,不慎忘記在父類中使用對象的合併引用這可能發生。考慮下面的例子

merge(A); 
B.setA(A); 
persist(B); 

在這種情況下,您合併A,但忘了用的A合併對象。要解決這個問題,你必須像這樣重寫代碼。

A=merge(A);//difference is here 
B.setA(A); 
persist(B); 
1

還有另外一種可能會導致hibernate出現此錯誤。您可以將未保存的對象A的引用設置爲附屬實體B並希望保留對象C。即使在這種情況下,你也會得到上述錯誤。

3

直到你真的必須使用Cascade.AllRolePermission有雙向manyToMany的關係。然後下面的代碼將工作正常

Permission p = new Permission(); 
    p.setName("help"); 
    Permission p2 = new Permission(); 
    p2.setName("self_info"); 
    p = (Permission)crudRepository.save(p); // returned p has id filled in. 
    p2 = (Permission)crudRepository.save(p2); // so does p2. 
    Role role = new Role(); 
    role.setAvailable(true); 
    role.setDescription("a test role"); 
    role.setRole("admin"); 
    List<Permission> pList = new ArrayList<Permission>(); 
    pList.add(p); 
    pList.add(p2); 
    role.setPermissions(pList); 
    crudRepository.save(role); 

而如果對象只是一個「新」的一個,那麼它會拋出相同的錯誤。

+0

是100%正確的,Cascade.All是懶惰的解決方案,只有在需要時才應用。首先,如果實體已經存在,檢查它是否加載到當前實體管理器中,如果沒有加載它。 – 2017-03-03 16:43:28

0

錯誤的一個可能的原因是沒有設置父實體的值;例如,對於一個部門,員工的關係,你必須爲了修正這個錯誤,寫這篇文章:

Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with @RequestParam String department 
employee.setDepartment(dept); 
0

有此錯誤其他一些可能性也在增加頁面或編輯頁面的這麼多的可能性。在我的情況下,我試圖挽救一個對象AdvanceSalary。問題是,在編輯AdvanceSalary employee.employee_id爲空因爲編輯時我沒有設置employee.employee_id。我做了一個隱藏的領域並設置它。我的代碼工作得很好。

@Entity(name = "ic_advance_salary") 
    @Table(name = "ic_advance_salary") 
    public class AdvanceSalary extends BaseDO{ 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     @Column(name = "id") 
     private Integer id; 

     @ManyToOne(fetch = FetchType.EAGER) 
     @JoinColumn(name = "employee_id", nullable = false) 
     private Employee employee; 

     @Column(name = "employee_id", insertable=false, updatable=false) 
     @NotNull(message="Please enter employee Id") 
     private Long employee_id; 

     @Column(name = "advance_date") 
     @DateTimeFormat(pattern = "dd-MMM-yyyy") 
     @NotNull(message="Please enter advance date") 
     private Date advance_date; 

     @Column(name = "amount") 
     @NotNull(message="Please enter Paid Amount") 
     private Double amount; 

     @Column(name = "cheque_date") 
     @DateTimeFormat(pattern = "dd-MMM-yyyy") 
     private Date cheque_date; 

     @Column(name = "cheque_no") 
     private String cheque_no; 

     @Column(name = "remarks") 
     private String remarks; 

     public AdvanceSalary() { 
     } 

     public AdvanceSalary(Integer advance_salary_id) { 
      this.id = advance_salary_id; 
     } 

     public Integer getId() { 
      return id; 
     } 

     public void setId(Integer id) { 
      this.id = id; 
     } 

     public Employee getEmployee() { 
      return employee; 
     } 

     public void setEmployee(Employee employee) { 
      this.employee = employee; 
     } 


     public Long getEmployee_id() { 
      return employee_id; 
     } 

     public void setEmployee_id(Long employee_id) { 
      this.employee_id = employee_id; 
     } 

    } 
0

如果你使用Spring數據JPA那麼除了@Transactional註釋爲您服務的實施將解決這一問題。

0

我遇到了這個異常,當我沒有堅持父對象,但我救了孩子。爲了解決這個問題,在同一個會話中,我堅持使用子對象和父對象,並在父對象上使用CascadeType.ALL。

0

爲了完整起見:一個

org.hibernate.TransientPropertyValueException 

有消息

object references an unsaved transient instance - save the transient instance before flushing 
當您嘗試堅持/帶至這恰好是 另一個實體的引用合併的實體

也將發生分離

相關問題