Java 在“中插入值”;“另一边”;JPA中的1对n关系(使用EclipseLink)
我有一个应用程序使用JSF2、JPA2和EJB3.1在GlassfishV3上运行(因此它使用EclipseLink 2)。此应用程序有两个JPA实体,Java 在“中插入值”;“另一边”;JPA中的1对n关系(使用EclipseLink),java,jpa,jpa-2.0,eclipselink,glassfish-3,Java,Jpa,Jpa 2.0,Eclipselink,Glassfish 3,我有一个应用程序使用JSF2、JPA2和EJB3.1在GlassfishV3上运行(因此它使用EclipseLink 2)。此应用程序有两个JPA实体,Person和Message,每个Message都有两个Person的引用,即消息发送方和消息接收方。Person类具有属性,提供对已发送或已接收的消息的访问。消息类是这样的: @Entity public class Message { @ManyToOne @JoinColumn(name="sender") priv
Person
和Message
,每个Message
都有两个Person
的引用,即消息发送方和消息接收方。Person
类具有属性,提供对已发送或已接收的消息的访问。消息
类是这样的:
@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 ...
}
然而,令人惊奇的事情发生了。当我注释掉标记为[1]
和[2]
的行并调用该方法时,当我在其他地方使用这些实体时,发送方的发送消息和接收方的接收消息列表中不会出现该消息,即使它们是从实体管理器中检索的(例如通过EntityManager.find()
)。如果我取消注释它,那么消息将按预期出现在列表中
我觉得这很有趣,因为我设想了两种情况,当这些行被注释掉时:
- 直接从数据库中检索
发送方
和接收方
实体,消息应该出现在它们的列表中,因为我保存了消息,因此关系将保留在数据库中;或
发送方
和接收方
实体从某些缓存中检索,因此它们已经将消息添加到列表中
显然,它不是这样工作的
我在Hibernate中找到了关于缓存的信息。基于此,我认为问题在于,由于缓存不是对象而是值,因此需要使用EntityManager.merge()
方法“刷新”具有缓存值的实体
是这样吗?如果没有,这种行为的原因是什么?调用EntityManager.merge()
是最好的解决方案吗
提前谢谢大家 我的理解是,当您持久化消息时,接收方和发送方实体不会自动保存到数据库中
我认为您应该正确设置级联选项。也许这篇文章会有所帮助
问题在于您违反了对象标识。您的person对象来自不同的事务,因此将分离不同的持久性单元和。通过从新消息中引用它们,您已经损坏了持久性单元,因为您现在知道如何从托管对象中引用分离的对象。i、 e.如果你为任何一个人做一个find(),你会得到另一个人
您应该首先在当前事务/持久性上下文中查找()每个人,然后与他们一起创建消息,或者在新消息上使用merge()而不是persist(),作为与分离对象的merge
创建后,消息对象不在人员的消息中的原因是,您使用的是共享缓存(EclipseLink的默认设置),并且如果没有合并,您从未将消息添加到受管人员对象(仅分离的对象)。因为manytone定义了数据库中的关系,所以可以禁用缓存,或者调用person上的refresh来获取正确的消息。但是,正确的解决方案是不要损坏对象模型
看,,
我认为不必保存发送者和接收者,因为关系是在消息
端注册的。此外,我看不到任何级联(实际上可能是删除级联)的原因,因为持久化
级联不起作用(个人
s已经持久化),并且合并
级联也不起作用。但是我可能会错过一些东西。。。(OTOH,非常感谢这篇文章,它真的很棒)。
@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;
}
}