2014-09-04 53 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

相关问题