【发布时间】:2011-03-23 18:59:47
【问题描述】:
我有一个使用 JSF 2、JPA 2 和 EJB 3.1 在 GlassFish v3 上运行的应用程序(因此它使用 EclipseLink 2)。此应用程序有两个 JPA 实体,Person 和 Message,每个 Message 都有两个 Persons 的引用,即消息发送者和消息接收者。 Person 类具有提供对发送或接收的Messages 的访问的属性。 Message 类是这样的:
@Entity
public class Message {
@ManyToOne
@JoinColumn(name="sender")
private Person sender;
@ManyToOne
@JoinColumn(name="receiver")
private Person receiver;
// ... some stuff ...
}
Person 类如下:
@Entity
public class Person {
@OneToMany(fetch=FetchType.EAGER, mappedBy="sender")
private List<Message> sentMessages;
@OneToMany(fetch=FetchType.EAGER, mappedBy="receiver")
private List<Message> receivedMessages;
// ... more stuff ...
}
Message 实例是通过 DAO 类中的方法创建的:
@Stateless
public class MessageDAOImpl implements MessageDAO {
public Message crete(Person sender, Person receiver) {
Message message = new Message();
message.setSender(sender);
message.setReceiver(receiver);
entityManager.persist(message);
// Puting in other objects, hoping it will work
sender.getSentMessages().add(message);
receiver.getReceivedMessages().add(message);
// Saving sender and receiver: here comes the interesting part
entityManager.merge(sender); // [1]
entityManager.merge(receiver); // [2]
return message;
}
}
然而,令人惊奇的事情发生了。当我注释掉标记为[1] 和[2] 的行并调用该方法时,当我在其他地方使用这些实体时,该消息不会出现在sender 的已发送消息和receiver 的已接收消息列表中,即使它们是从实体管理器中检索的(例如通过EntityManager.find())。如果我取消注释,则消息会按预期出现在列表中。
我觉得这很有趣,因为我为注释掉行的情况设想了两种情况:
-
sender和receiver实体直接从数据库中检索,消息应该出现在它们的列表中,因为我保存了消息,因此关系保留在数据库中;或 -
sender和receiver实体是从某个缓存中检索到的,因此它们已经将消息添加到列表中。
显然,这种方式是行不通的。
我发现这个awesome article 关于 Hibernate 中的缓存。基于此,我认为问题在于,由于缓存不是对象而是值,因此需要 EntityManager.merge() 方法来“刷新”具有缓存值的实体。
是这样吗?如果不是,这种行为的原因是什么?拨打EntityManager.merge() 是最好的解决方案吗?
提前谢谢大家!
【问题讨论】:
标签: java jpa jpa-2.0 eclipselink glassfish-3