为什么我不修改我的实体而不坚持他的属性?

时间:2014-09-04 13:30:11

标签: jpa

我创建了一个名为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尝试创建用户关联邮件。如果有人知道为什么他能告诉我吗?

1 个答案:

答案 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中涉及的所有对象,进行更改并提交事务。