我有使用JSF 2,JPA 2和EJB 3.1在GlassFish v3的運行(因此它使用的EclipseLink 2)的應用程序的1到n的關係的「另一側」插入的值。此應用程序有兩個JPA實體,Person
和Message
,每個Message
都有兩個Person
s的參考,即消息發送方和消息接收方。類別Person
具有提供對發送或接收的訪問的屬性Message
。該Message
類是這樣的:中的在JPA(使用的EclipseLink)
@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()
是最佳解決方案嗎?
謝謝大家提前!
我不認爲它應該是必要的,因爲關係在'Message'側登記保存發送者和接收者。另外,我沒有看到任何級聯的原因(實際上可能是刪除級聯),因爲「PERSIST」級聯不起作用(「人員」已經被保留)並且「MERGE」級聯不會遵循。但是我可能會錯過一些東西......(OTOH,非常感謝這篇文章,這真的很棒)。 – brandizzi 2011-03-24 20:53:31