我创建了一个名为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表中插入;在表User中,名称是唯一的,因此它不起作用,我不知道为什么glassfich尝试创建用户关联邮件。如果有人知道为什么他能告诉我吗?
答案 0 :(得分: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中涉及的所有对象,进行更改并提交事务。