2012-11-22 95 views
1

我有一個Entity與標記爲CascadeType.ALL的雙向ManyToMany關係(在同一實體上)。如何在標有CascadeType.ALL的關係中添加持久實體?

這裏是如何將查找Contact實體:

@ManyToMany(cascade= CascadeType.ALL) 
private List<Contact> parentContacts = new ArrayList<Contact>(); 
@ManyToMany(cascade= CascadeType.ALL, mappedBy="parentContacts") 
private List<Contact> childContacts = new ArrayList<Contact>(); 

我有應該在服務器端的方法做保存這個實體:

public AltContact saveContact(EntityManager em, Contact contact, List<Contact> childs) { 
    for (Contact c : childs) { 
     contact.getChildContacts().add(c); 
     c.getParentContacts().add(contact); 
    } 
    if (contact.getId() == null) { 
     em.persist(contact); 
    } else { 
     contact = em.merge(contact); 
    } 
    return contact; 
} 

它的偉大工程,如果contactchilds列表中的任何實體都不會被保留。但有時我會需要使用saveContact法已經堅持實體,當我嘗試這樣做,好像JPA嘗試堅持的關係的所有實體,然後將引發異常:

Internal Exception: java.sql.SQLIntegrityConstraintViolationException 

事實上,它會試圖改變並已經堅持實體,所以Contact的ID字段的唯一性將被違反。

如何激活?我的方法有什麼問題?

我該如何讓Eclipselink/JPA不嘗試堅持屬於關係且已經存在的實體的實體?

回答

2

如果你的父母聯繫實體是新的,但有些孩子存在(但分離),你不想調用堅持父母 - 這將導致持續層疊到需要引起的孩子立即拋出異常或在刷新/提交時拋出異常。如果您希望對新的聯繫人致電perist,那麼您應該嘗試查找現有的子項並將託管實例關聯到新聯繫人。如果它不存在,你可以單獨堅持孩子,或允許堅持逐級關係爲你做。

通常情況下,只需在新的父聯繫人上調用合併,並讓提供者判斷它是否應該是更新或插入,就容易得多。自從合併級聯到子級後,它們也會根據需要插入或更新。

請注意使用級聯。當你去除一個父母時,它也會把這個去除級聯到子級,然後級聯到他們父級集合中的每個父級。如果管理不當,可能會無意中刪除所有聯繫人。還要注意,導致孩子從列表中刪除的更改可能無法正確級聯 - 級聯合並只能對當前在集合中的實體進行操作,而不是曾經在那裏的實體。所以你可能需要手動調用合併兒童從父母的集合中刪除它們,或確保他們已通過不同的路徑調用合併。

相關問題