0

我被困在一個點,我試圖更新@OneToMany映射。更新@OneToMany集合時發生的問題

問題: 我有2個實體:標準和任務。一個標準可以包含多個任務。

class Criteria { 
    @OneToMany(mappedBy = "criteria", cascade = { CascadeType.PERSIST, 
    CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY) 
    @Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE, 
       org.hibernate.annotations.CascadeType.ALL, 
       org.hibernate.annotations.CascadeType.MERGE, 
       org.hibernate.annotations.CascadeType.PERSIST }) 
    private Set<Task> tasks; 
} 

class Task { 
    @ManyToOne 
    @JoinColumn(name = "CRITERIA_ID", nullable=false) 
    private Criteria criteria; 
} 

我想更新與新的組任務的現有標準。這需要刪除所有現有任務並添加新任務。 這裏是我怎麼做的:

criteriaDao.persist(criteria); 
Set<Task> existingTasks=criteria.getTasks(); 
if(existingTasks != null) { 
    for (Task task : existingTasks) { 
     task.setCriteria(null); 
    } 
    criteria.setTasks(tasks); 
    //more code which sets criteria for each task - this works if i try to save new criteria with new tasks 
} 

休眠拋出一個異常:

Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (CCA_DEV_5.TASK__UN) violated 

,拋出此異常,因爲它沒有刪除現有任務。

如果我只是刪除所有的任務,它完美的作品,並取消了與下面的代碼給定條件的所有任務:

criteriaDao.persist(criteria); 
Set<Task> existingTasks=criteria.getTasks(); 
if(existingTasks != null) { 
    for (Task task : existingTasks) { 
    task.setCriteria(null); 
} 
} 

我嘗試添加新的任務和更多的東西后,使用合併的所有選項,但沒有什麼似乎爲我工作。我被困在這裏,肯定錯過了Hibernate中非常基本的東西。

在此先感謝。

回答

0

在你的Task類中,你應該完全沒有提及Criteria。只需將其與其註釋一起刪除即可。

然後,而不是設置Task引用的Criteria,因爲此參考不再存在,只需使用criteria.setTasks(newTasks)並保存criteria


讓我解釋一下。 CriteriaTask之間的關係爲oboviusly Criteria 1 --- n Tasks - 1至n。現在,你可以撥打one-to-many關係,你可以稱它爲many-to-one,這取決於你的觀點。從Criteria看,它的one-to-many,而從Task角度來看 - 這是many-to-one。一般而言,選擇一個這些觀點是可取的和更直觀的,並且堅持它。選擇一個觀點,定義了「控制」任何修改應該適用的關係的實體。

在你的情況,如果你把一個Criteria含有或擁有一套Task小號- 你會處理關係爲one-to-many。在決定之後,在Task的java類中不需要Criteria參考。您只能使用Criteria API(在DB中爲Task創建的表格,但確實有一個引用其包含Criteria的列)的關係。

+0

嗯......在我看來,多對一應該與一對多一起工作,我還沒有看到任何問題。另外JPA支持逆映射。我得到這個固定由(任務任務:existingTasks)設置與新集收集收藏 - 之前添加以下行{ task.setCriteria(NULL); } => session.flush(); criteria.setTasks(tasks); 這確保刪除語句在插入之前執行。 –

+0

@RakeshSinha你很好,你解決了這個問題。不過,我建議你閱讀[這個簡短的親子休眠文檔示例](http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#example-parentchild-bidir)這解釋瞭如何以'一對多'關係使用'inverse'。 – yair

+0

謝謝,我在過去看過這個文檔,並且使用相同的。你認爲還有另一種實現我所做的事情的方式嗎?調用flush()會顯式工作,但會導致實體管理器將所有查詢都刷新到Db。有更好的方法來更新一個集合。 –