У меня есть приложение, использующее JSF 2, JPA 2 и EJB 3.1, работающее на GlassFish v3 (поэтому оно использует EclipseLink 2). Это приложение имеет два объекта JPA, Person
и Message
, и каждый Message
имеет ссылку на два Person
s, отправителя сообщения и получателя сообщения. Класс Person
имеет атрибуты, обеспечивающие доступ к отправленным или полученным Message
с. Класс 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
извлекаются из некоторого кэша, поэтому в них уже добавлены сообщения.
Видимо, так не работает.
Я нашел эту потрясающую статью о кеше в Hibernate. Исходя из этого, я размышляю о том, что проблема заключается в том, что, поскольку кэш состоит не из объектов, а из значений, требуется метод EntityManager.merge()
для «обновления» сущностей с помощью кэшированных значений.
Это так? Если нет, то в чем причина такого поведения? Является ли звонок EntityManager.merge()
лучшим решением?
Спасибо всем заранее!