I have a model like this:
class Message {
@Id
private UUID id;
// ...
@OneToMany(mappedBy = "messageId")
private List<Value> values;
}
class Value {
private UUID messageId;
}
The Value
entities are being created in a JPA session, then, in another session, I create a Message
in which I provide the id
myself (which matches the messageId
of existing Value
).
After I have persisted the Message
, when I try to call getValues()
from it, I get null
. What's the best way to solve this? Can I programmatically fetch the relation? Should I open another session?
CodePudding user response:
Solution 1: explicitly initialize child entities during parent entity creation
Main idea of that solution is to create an additional method for loading Value
entities by messageId
in ValueRepository
and use it explicitly to initialize values collection during Message
entity creation.
Repository for loading Value entities:
public interface ValueRepository extends JpaRepository<ValueEntity, Long> {
@Query("SELECT v FROM ValueEntity v WHERE v.messageId = :messageId")
List<ValueEntity> findByMessageId(Long messageId);
}
Mesage creation and values collection initialization:
public Message createMessage() {
Message message = new Message();
message.setId(1L);
message.setValues(valueRepository.findByMessageId(message.getId()));
entityManager.persist(message);
return message;
}
Solution 2: perform Flush and Refresh
AfterMessage
persists operation you can perform Flush operation, which will synchronize entity with database state, and then Refresh operation, which will reread the state of the given entity.
public Message createMessage() {
Message message = new Message();
message.setId(1L);
entityManager.persist(message);
entityManager.flush();
entityManager.refresh(message);
return message;
}
I think Solution 1 is preferable, it is better from a performance perspective because the flush operation can take additional time.
UPDATE:
In case of merge operation, use returned persisted entity for the refresh, instead of init object.
public Message createMessage() {
Message message = new Message();
message.setId(1L);
Message persistedMessage = entityManager.merge(message);
entityManager.flush();
entityManager.refresh(persistedMessage);
return persistedMessage;
}
Or better divide save and update operations
public Message saveOrUpdateMessage() {
Message message = entityManager.find(Message.class, 1L);
if (message == null) {
//handle new entity save
message = new Message();
message.setId(1L);
entityManager.persist(message);
entityManager.flush();
entityManager.refresh(message);
}
//handle existing entity update
ValueEntity valueEntity = new ValueEntity();
valueEntity.setId(2L);
valueEntity.setMessageId(message.getId());
entityManager.persist(valueEntity);
message.getValues().add(valueEntity);
return message;
}