2011-01-10 53 views
2

我的域模型與關係管理自我參照的雙向關係中的實體來完成:問題在JPA管理雙向關係:從集合中移除

@Entity 
public class Users implements BaseEntity<String>, Serializable { 

    @Id 
    private String username; 
    @ManyToMany(cascade = {CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST}) 
    private List<User> associatedSenders; 
    @ManyToMany(mappedBy = "associatedSenders") 
    private List<User> associatedReceivers; 

    // 
    // Associated Senders 
    // 
    public List<User> getAssociatedSenders() { 
     if (associatedSenders == null) { 
      associatedSenders = new ArrayList<User>(); 
     } 

     return associatedSenders; 
    } 

    public void addAssociatedSender(User sender) { 
     if (associatedSenders == null) { 
      associatedSenders = new ArrayList<User>(); 
     } 

     associatedSenders.add(checkNotNull(sender)); 
     if (!sender.getAssociatedReceivers().contains(this)) { 
      sender.addAssociatedReceiver(this); 
     } 
    } 

    public void removeAssociatedSender(User sender) { 
     if (associatedSenders == null) { 
      associatedSenders = new ArrayList<User>(); 
     } 

     associatedSenders.remove(checkNotNull(sender)); 
     if (sender.getAssociatedReceivers().contains(this)) { 
      sender.removeAssociatedReceiver(this); 
     } 
    } 

    public void setAssociatedSenders(List<User> senders) { 
     checkNotNull(senders); 

     if (associatedSenders == null) { 
      associatedSenders = new ArrayList<User>(); 
     } 

     // first remove all previous senders 
     for (Iterator<User> it = associatedSenders.iterator(); it.hasNext();) { 
      User sender = it.next(); 
      it.remove(); 
      if (sender.getAssociatedReceivers().contains(this)) { 
       sender.removeAssociatedReceiver(this); 
      } 
     } 

     // now add new senders 
     for (User sender : senders) { 
      addAssociatedSender(sender); 
     } 
    } 

    // 
    // Associated Receivers 
    // 
    public List<User> getAssociatedReceivers() { 
     if (associatedReceivers == null) { 
      associatedReceivers = new ArrayList<User>(); 
     } 

     return associatedReceivers; 
    } 

    /** 
    * <p><b>Note:</b> this method should not be used by clients, because it 
    * does not manage the inverse side of the JPA relationship. Instead, use 
    * the appropriate method at the inverse of the relationship. 
    * 
    * @param receiver 
    */ 
    protected void addAssociatedReceiver(User receiver) { 
     if (associatedReceivers == null) { 
      associatedReceivers = new ArrayList<User>(); 
     } 

     associatedReceivers.add(checkNotNull(receiver)); 
    } 

    /** 
    * <p><b>Note:</b> this method should not be used by clients, because it 
    * does not manage the inverse side of the JPA relationship. Instead, use 
    * the appropriate method at the inverse of the relationship. 
    * 
    * @param receiver 
    */ 
    protected void removeAssociatedReceiver(User receiver) { 
     if (associatedReceivers == null) { 
      associatedReceivers = new ArrayList<User>(); 
     } 

     associatedReceivers.remove(checkNotNull(receiver)); 
    } 
} 

當我添加新的用戶實體到associatedSenders集合,一切都按預期工作。數據庫中的表得到正確更新,並且內存中的關係也是正確的。但是,當我從associatedSenders集合(或該集合中的所有實體)中刪除用戶實體時,例如做這樣的呼籲:

List<User> senders = Collections.emptyList(); 
user.setAssociatedSenders(senders) 

數據庫表中得到正確更新,但em.find(User.class, username),其中username是誰曾是associatedSenders收集用戶的ID,下次調用揭示了associatedReceivers集合(反面)未被正確更新。也就是說,user仍然在那個集合中。只有當我通過em.refresh()刷新實體時,集合才能正確更新。看起來實體管理器在這裏做了一些緩存,但這種行爲對我來說似乎不正確。

UPDATE可能值得一提的是,我正在修改JSF受管bean內前端的用戶實體,即實體處於分離狀態。

+0

'equals()`/`hashCode()`是否正確實現? – axtavt 2011-01-10 16:34:10

+0

@axtavt是的,他們是。在這兩種情況下,我都使用用戶名來完成這項工作。 – Theo 2011-01-10 17:12:40

回答

3

如果要修改的對象,而這是分離,那麼你必須合併()它回到持久單元。由於您正在修改源對象和目標對象,因此必須合併()兩個對象以維護關係的兩側。級聯合並是不夠的,因爲你已經刪除了對象,所以沒有什麼可以級聯的。

您還可以在合併之後以及提交之前和之後檢查對象的狀態。

也許包含您的合併代碼。

0

唯一的解釋我可以計算出,用戶對象,您設置空單的associatedSender字段不是原來的緩存對象,它僅僅是一個副本...

+0

用戶對象通過`em.find()`檢索,不會被複制到任何地方。對它的修改是在分離狀態下執行的(在JSF託管bean中)。 – Theo 2011-01-11 07:51:54