2014-09-04 52 views
0

我創建了一個名爲Mail的jpa實體,它有兩個外鍵。爲什麼我不能修改我的實體而不保留其屬性?

public class Mail implements Serializable { 


@ManyToOne(optional = false, fetch = FetchType.LAZY) 

@JoinColumn(name = "auteur") 
private User user; 

@JoinColumn(name = "typeC") 
@ManyToOne(optional = false, fetch = FetchType.LAZY) 
private Type typeMail; 
.... 

,當我要修改一個郵件,我這樣做:

public void modifyMail(Mail mail) { 
    Mail m = em.find(Mail.class, mail.getId()); 
    m.setUser(mail.getUser()); 
    m.setType(mail.getType()); 
    em.persist(m); 
} 

,但它不工作。在glassfich日誌中,「em.persist」工作正常,但glassfich也指示在用戶表中插入;在表User中,名稱是唯一的,所以它不起作用,我不知道爲什麼glassfich嘗試創建與郵件關聯的用戶。如果有人知道爲什麼請他告訴我?

回答

0

實體管理器記錄您從中獲得的所有對象/實例。所以如果你使用em.find()來加載用戶,它會知道這個用戶實例。

如果您在關閉用於加載它們的事務後保留用戶實例,它們就會變陳舊。實體經理不再真正瞭解他們,並假定他們是新的。

所以上面的代碼需要:

public void modifyMail(Mail mail) { 
    Mail m = em.find(Mail.class, mail.getId()); 
    User u = em.find(User.class, mail.getUser().getId()); 
    m.setUser(u); 
    m.setType(mail.getType()); 
    em.persist(m); 
} 

public void modifyMail(Mail mail) { 
    Mail m = em.find(Mail.class, mail.getId()); 
    User u = em.refresh(mail.getUser()); 
    m.setUser(u); 
    m.setType(mail.getType()); 
    em.persist(m); 
} 

這樣做的原因是,實體管理器不知道什麼是「用戶」或「郵件」的意思。所有對象都是相同的。因此,如果您在某處更改用戶,則Mail中的用戶實例可能已過時。

但更好的辦法可能是,當Mail實例實際更改更改代碼:

em.getTransaction().begin(); 

    Mail mail = em.find(Mail.class, id); 
    User u = em.find(User.class, userId); 
    mail.setUser(u); 

    em.getTransaction().end(); 

因此,而不是收集的變化,開始交易,加載從EM涉及的所有對象,進行更改並提交交易。

+0

並且你可以添加「em.persist」不需要,因爲如果一個對象被「管理」,那麼對字段的任何更新都將被攔截。 – 2014-09-04 14:04:13

+0

@BillyFrost:真的嗎?我從來沒有試過這個;我認爲我需要對對象「提交」更改(並且我看到的每個示例最終都會調用persist())。但它看起來你是對的:http://www.objectdb.com/java/jpa/persistence/update – 2014-09-04 14:12:49

+0

非常感謝你我嘗試第一個代碼亞倫給與它的作品。 – Ediruth 2014-09-05 04:44:19

相關問題