Я в настоящее время перемещаю (рабочее) приложение от использования EclipseLink для Спящего режима JPA, главным образом это пошло вполне гладко, но я нахожу одну вещь, которую я не могу объяснить и также не могу думать ни о каких хороших критериях поиска!
В основном у меня есть четыре объекта со связями "один ко многим", формирующими цепочку:
EntityA имеет список EntityB, каждый из которых имеет список EntityC, каждый из которых имеют список EntityD
у каждого из тех затем есть many-one отношения, идущие другим путем, таким образом:
EntityD имеет EntityC, который имеет EntityB, который имеет EntityA.
Это (в большой степени уменьшено для ясности):
@Entity
public class EntityA {
@OneToMany (cascade = CascadeType.All, mappedBy = "entityA")
private List<EntityB> entityBList;
...
}
@Entity
public class EntityB {
@OneToMany (cascade = CascadeType.All, mappedBy = "entityB")
private List<EntityC> entityCList;
@JoinColumn (name = "ENTITY_A", referencedColumnName = "ENTITY_A_ID")
@ManyToOne (cascade = CascadeType.PERSIST, optional = false)
private EntityA entityA;
}
@Entity
public class EntityC {
@OneToMany (cascade = CascadeType.ALL, mappedBy = "entityC")
private List<EntityD> entityDList;
@JoinColumn (name = "ENTITY_B", referencedColumnName = "ENTITY_B_ID")
@ManyToOne (cascade = CascadeType.PERSIST, optional = false)
private EntityB entityB;
}
@Entity
public class EntityD {
@JoinColumn (name = "ENTITY_C", referencedColumnName = "ENTITY_C_ID")
@ManyToOne (cascade = CascadeType.PERSIST, optional = false)
private EntityC entityC;
}
Я получаю EntityA от базы данных (ищущий его ее первичным ключом) и таким образом получаю приятно заполненный экземпляр EntityA с PersistentBag для моего List<EntityB>
. Я вижу, что ленивая загрузка происходит, когда я разыменовываю это List<EntityB>
, и то же, повторенное для получения EntityCs от EntityB.
На данном этапе все - как я ожидаю, у меня есть EntityA, B и C все полностью заполненные со значениями от базы данных, но затем я пытаюсь получить свой EntityD от EntityC, и найти, что это является пустым.
Мой менеджер по объекту все еще открыт и активен в этой точке, и даже если я смотрю на нее в отладчике сразу после получения EntityA, я могу идти через отношения, до EntityC, и снова рассматривать 'entityDList' как пустой указатель.
Единственное решение, которое я нашел до сих пор, состоит в том, чтобы использовать:
EntityManager.refresh(entityC);
который заполняет все его элементы включая лениво загруженный PersistentBag для entityDList.
Так, мое предположение, это В спящем режиме, только заполняет ссылки 2 уровня глубоко (или 3, в зависимости от того, как Вы рассчитываете), и сдающийся после этого, хотя я действительно не понимаю, почему это было бы. Это имеет смысл кому-либо?
Есть ли какое-либо решение кроме .refresh? Некоторая конфигурация или значение аннотации, которое сделает, в спящем режиме, заполняют ссылки полностью вниз?
Спасибо за предложения от людей, которые, вероятно, актуальны, но не помогли в моем конкретном случае.
Если вы читаете это и сталкиваетесь с той же проблемой, возможно, стоит попробовать предложение max_fetch_depth
, но по какой-то причине у меня это не сработало (мне бы хотелось узнать, почему?) .
Аналогичным образом, если ваши @OneToMany
являются наборами, а не списками, выполнение активной выборки или левого соединения, как предлагает Альберт, может работать, но, очевидно, Hibernate позволяет вам иметь максимум 1 Список, который охотно выбирается, если вам нужно больше, ваши коллекции должны быть наборами. Я не пробовал, но подозреваю, что это могло решить проблему.
Если у кого-то нет лучшего предложения, я буду продолжать вызывать обновление, что в любом случае, вероятно, имеет больше смысла для моего приложения.
Это действительно смешно. Один из способов обойти это - запросить объект A с левым соединением для -> B-> C-> D, что также будет быстрее, если вы все равно собираетесь перейти к объекту D. Было бы что-то вроде этого.
"from A left join fetch B left join fetch C left join fetch D"
Вы тоже пытались установить отношения с C-> D нетерпеливо? Любопытно, что будет потом ...
В документации по спящему режиму сказано, что вы можете установить его с помощью свойства hibernate.max_fetch_depth. Значение по умолчанию - 3. Его можно найти в «Справочной документации по Hibernate» на стр. 47.