Scenario
A Spring Data JPA/Hibernate based application with @Transactional
services, thus entities are managed by the persistence provider with no explicit invoking of save
/update
/persist
.
Now, I'd like to implement a read-only repository/service for MyEntity
, while also keeping the non-read-only/CRUD ones -- ergo, annotating the entity @Immutable
will be too much and would not help.
Approach
Fetching entities within a read-only session (which we reset to non-read-only afterwards), here as a simplified example:
@Entity
public class MyEntity {
private long id;
@OneToMany // lazily-loaded as per default
private List<MyOtherEntity> otherEntities;
}
@Service
public class ReadOnlyService {
private final Repository repository;
private final EntityManager entityManager;
public MyEntity findAllByIds(Collection<Long> ids) {
return executeInReadOnlySession(() -> repository.findAllById(ids));
}
private <T> T executeInReadOnlySession(Supplier<T> operation) {
Session session = getSession();
session.setDefaultReadOnly(true);
T result = operation.get();
session.setDefaultReadOnly(false);
return result;
}
private Session getSession() {
return ((EntityManager) entityManager.unwrap(null)).unwrap(Session.class);
}
}
The issue with this approach
As such, this approach works fine. However, as MyEntity.otherEntities
is lazily-loaded, it's not being loaded within the read-only session. Once it's lazily loaded later on, the session has been reset to setDefaultReadOnly(false) and the list items in otherEntities
are not immutable. Moreover, MyOtherEntity
might have lazily-loaded relations itself.
Question
Is there a solution to make all of MyEntity
's lazily-loaded relationships read-only too (and also recursively all of lazily-loaded fields of MyOtherEntity
), without having to eagerly-load them within the read-only session?