gpt4 book ai didi

java - 在 JPA 中的 1 对 n 关系的 "other side"中插入值(使用 EclipseLink)

转载 作者:行者123 更新时间:2023-12-04 06:31:04 25 4
gpt4 key购买 nike

我有一个使用 JSF 2、JPA 2 和 EJB 3.1 在 GlassFish v3 上运行的应用程序(因此它使用 EclipseLink 2)。此应用程序有两个 JPA 实体,PersonMessage每个 Message有两个 Person 的引用s,消息发送者和消息接收者。 Person类具有提供对发送或接收的访问权限的属性 Message s。 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() ), 的接收消息列表也是如此。如果我取消注释,则消息会按预期出现在列表中。

我觉得这很有趣,因为我设想了在注释掉行的情况下的两种情况:
  • senderreceiver实体直接从数据库中检索,消息应该出现在它们的列表中,因为我保存了消息,因此关系保留在数据库中;或
  • senderreceiver实体是从某个缓存中检索的,因此它们已经将消息添加到列表中。

  • 显然,它不能以这种方式工作。

    我找到了 awesome article关于 Hibernate 中的缓存。基于此,我认为问题在于,由于缓存不是对象而是值, EntityManager.merge()使用缓存值“刷新”实体需要方法。

    是这样吗?如果不是,这种行为的原因是什么?正在调用 EntityManager.merge()最好的解决方案?

    谢谢大家!

    最佳答案

    问题是您违反了对象身份。您的人员对象来自不同的事务,因此不同的持久性单元并且是分离的。通过从您的新消息中引用它们,您已经破坏了您的持久性单元,因为您现在如何从托管对象中引用分离的对象。即,如果您为任何一个人执行 find(),您将得到另一个人。

    您应该首先 find() 当前事务/持久性上下文中的每个人,然后与他们一起创建消息,或者在新消息上使用 merge() 而不是 persist() 作为与解析分离对象的合并。

    创建后消息对象不在人员消息中的原因是您正在使用共享缓存(默认使用 EclipseLink),并且在没有合并的情况下,您从未将消息添加到托管人员对象(仅分离的)。由于 ManyToOne 定义了数据库中的关系,您可以禁用缓存,或在人员上调用 refresh 并获取正确的消息。但是,正确的解决方案是不要破坏您的对象模型。

    看,
    http://en.wikibooks.org/wiki/Java_Persistence/Caching#Object_Identity

    关于java - 在 JPA 中的 1 对 n 关系的 "other side"中插入值(使用 EclipseLink),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5410218/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com