2012-10-31 51 views
14

我在這裏的問題與我的其他問題幾乎相似Explicit delete on JPA relationships 但我想進一步簡化它以保證更詳細的答案。爲什麼合併不是級聯在一對多關係上

想象一下,我有一個父母和孩子之間的OneToMany關係。

@Entity 
public class Parent { 
    private String name; 
    @OneToMany(mappedBy="owner",cascade=CascadeType.ALL, fetch=FetchType.EAGER) 
    private List<Child> children; 
} 
@Entity 
public class Child { 
    private String name; 
    @ManyToOne 
    private Parent owner; 
} 

在我的用戶界面中,我顯示了父級列表。用戶可以選擇一位家長,並且他/她可以編輯其子女的列表。 爲了表明這一點,我使用了一個currentParent變量來表示當前編輯的父級。 用戶可以選擇添加/編輯孩子的名字。

單擊按鈕後,我會使用EJB調用保存新的子項列表。

@ViewScoped 
public class MyBean(){ 
    private Parent currentParent; 
    @EJB 
    private MyEJB myEJB; 

    public void saveChanges(){ 
     myEJB.save(currentParent); 
    } 
} 

我的EJB調用如下所示。

@Stateless 
public class MyEJB{ 
    @PersistenceContext(unitName = "MyPU") 
    private EntityManager em; 

    public void save(Parent parentNew){ 
     Parent pOld = em.find(entityClass, p.getId()); 
     if(pOld !=null){ 
      pOld.setName(parentNew.getName()); 
      pOld.setChildren(parentNew.getChildren()); 
      em.merge(pOld); 
     } 
    } 
} 

我的問題是,我能夠更改父的名字,但對兒童列表中的任何改變不會反映到數據庫。 它不會更改或執行任何SQL來刪除/更新/添加子項。

可能是什麼原因?

UPDATE

經過一些試驗和錯誤嘛,讀通各個環節,似乎在我的@OneToMany設置orphanRemoval選項就可以解決我的問題。 Eclipselink會在合併期間自動刪除孤立行。

這麼多的JPA複雜..

@Entity 
public class Parent { 
    private String name; 
    @OneToMany(mappedBy="owner",cascade=CascadeType.ALL, fetch=FetchType.EAGER,orphanRemoval = true) 
    private List<Child> children; 
} 
+0

也許這將有助於:http://stackoverflow.com/questions/10656765/handling-collection-updates-with-jpa – JMelnik

+0

嗨,我不知道如果我從那個鏈接得到的答案,所以你的意思是我有循環收集並逐一保存?我真的認爲eclipselink會處理我的收藏的保存?例如,我在一個實體中有5個孩子,然後我只用兩個孩子編輯它,當我調用合併操作時,它將負責刪除/添加行。謝謝 –

回答

1

你的問題What could be the cause?。原因是價值內容爲parentNew。如果parentNew是以下原因之一,則不會影響/更新爲子項。

  1. 沒有參考實例父母和孩子vise簽證。 --->它會拋出異常。
  2. Parent參數值爲空或空列表Clild - >這將是您的原因。
  3. Child不會從UI更新名稱。 - >這將是您的原因。

例子。我快速寫它。沒關係。

在DB

Parent      Child 
================== ======================================= 
'P001', 'Parent 1' 'C002', 'Child 2', 'P001' 
        'C003', 'Child 3', 'P001' 
        'C001', 'Child 1', 'P001' 

數據已經存在Upldated後:

Parent      Child 
==================   ======================================= 
'P001', 'Update Parent 1' 'C002', 'Update Child 2', 'P001' 
          'C003', 'Update Child 3', 'P001' 
          'C001', 'Update Child 1', 'P001' 

List<Child> clidList = new ArrayList<Child>(); 
Parent parent = new Parent("P001", "Update Parent 1", clidList); 
Child c1 = new Child("C001", "Update Child 1", parent); 
Child c2 = new Child("C002", "Update Child 2", parent); 
Child c3 = new Child("C003", "Update Child 3", parent); 
clidList.add(c1); 
clidList.add(c2); 
clidList.add(c3); 

Parent existingParent = em.find(Parent.class, parent.getId()); 
existingParent.setName(parent.getName()); 
existingParent.setChildren(parent.getChildren()); 
em.merge(existingParent); 
5

這是一個標準的問題與合併。拾取集合中子對象的更改。

合併調用只能級聯列表中的對象,因此不在列表中的對象的更改會丟失。不幸的是,OneToMany並不擁有這種關係:孩子的ManyToOne會這樣做。因此,需要將子實體合併,才能看到並推送到數據庫。子實體是獨立的對象,需要在更改時單獨合併。那,或者添加到不同的父/樹來合併。

+0

你好,謝謝你的信息,那麼你建議我做什麼? –

+1

任意數量的選項。如果可能的話,可以將它們添加到不同的父項中。或者,如果他們不能獨立於他們的父母,請將他們標記爲孤兒移除,以便在取消引用時將其刪除。或者通過先找到父對象並修復傳遞給對象的對象中缺少的子對象來處理父對象的合併調用中的集合差異 - 這甚至可以在事件中實現。或者只是確保應用程序調用它從父項中移除的子項的合併。 – Chris

相關問題