Используя JPA2 / Hibernate, я создал объект A, который имеет однонаправленное отображение на объект X (см. Ниже). Внутри A у меня также есть временный член "t", который я пытаюсь вычислить, используя метод @PostLoad. Расчет требует доступа к ассоциированным X:
@Entity
public class A {
// ...
@Transient
int t;
@OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)
private List listOfX;
@PostLoad
public void calculateT() {
t = 0;
for (X x : listOfX)
t = t + x.someMethod();
}
}
Однако, когда я пытаюсь загрузить эту сущность, я получаю ошибку «org.hibernate.LazyInitializationException: недопустимый доступ к загрузке коллекции».
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:363)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentBag.get(PersistentBag.java:445)
at java.util.Collections$UnmodifiableList.get(Collections.java:1154)
at mypackage.A.calculateT(A.java:32)
Глядя на код hibernate (AbstractPersistentCollection.java) во время отладки, я обнаружил, что:
1) Мой метод @PostLoad вызывается ДО инициализации элемента listOfX
2) В коде Hibernate есть явная проверка, чтобы предотвратить инициализацию загруженной коллекции во время @PostLoad:
protected final void initialize(boolean writing) {
if (!initialized) {
if (initializing) {
throw new LazyInitializationException("illegal access to loading collection");
}
throwLazyInitializationExceptionIfNotConnected();
session.initializeCollection(this, writing);
}
}
Единственный способ исправить это - прекратить использование @PostLoad и переместить код инициализации в метод доступа getT (), добавив синхронизированный блок. Однако я хочу этого избежать.
Итак, есть ли способ выполнить активную выборку до вызова @PostLoad? Я не знаю, как это сделать в JPA, поэтому я надеюсь, что есть кое-что, чего я не знаю.
Кроме того, возможно, в проприетарном API Hibernate есть что-то для управления этим поведением?