Hibernate JPA - отношения ManyToOne не заселены - PullRequest
6 голосов
/ 29 июня 2010

В настоящее время я перемещаю (работающее) приложение из EclipseLink в Hibernate JPA, в основном все прошло довольно гладко, но я нахожу одну вещь, которую не могу объяснить, а также не могу придумать ни одного хорошего поиска. термины!

По сути, у меня есть четыре сущности с отношениями один-ко-многим, образующими цепочку:

EntityA имеет список EntityB, каждый из которых имеет список EntityC, каждый из которых имеет список EntityD

тогда каждый из них имеет отношение многие-к-одному, идущее в другую сторону, поэтому:

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>, и то же самое повторяется для получения EntityC от EntityB.

На данный момент все, как я и ожидал, у меня есть EntityA, B и C, все они полностью заполнены значениями из базы данных, но затем я пытаюсь получить свой EntityD из EntityC, и обнаружил, что он нулевой.

Мой менеджер сущностей все еще открыт и активен на этом этапе, и даже если я смотрю на него в отладчике сразу после получения EntityA, я могу пройти через отношения, вплоть до EntityC, и снова увидеть «entityDList» как ноль.

Единственное решение, которое я нашел до сих пор, это использовать:

EntityManager.refresh(entityC);

, который заполняет все его элементы, включая лениво загруженный PersistentBag для entityDList.

Итак, я предполагаю, что Hibernate заполняет ссылки только на 2 уровня глубиной (или 3, в зависимости от того, как вы рассчитываете) и сдается после этого, хотя я не очень понимаю, почему это будет. Это имеет смысл для кого-либо?

Есть ли какое-либо решение, кроме .refresh? Какое-то значение конфигурации или аннотации, которое заставит Hibernate заполнить ссылки до конца?

Ответы [ 3 ]

3 голосов
/ 07 июля 2010

Спасибо предложениям людей, которые, вероятно, актуальны, но не помогли в моем конкретном случае.

Если вы читаете эту статью, столкнувшись с той же проблемой, возможно, стоит попробовать max_fetch_depthпредложение, но по какой-то причине оно не сработало для меня (я бы с радостью посоветовал, почему?)или левое соединение, как предположил Альберт, может сработать, но очевидно, что Hibernate позволяет вам иметь максимум 1 список, который охотно выбирается, если вам нужно больше, ваши коллекции должны быть наборами.Я не пробовал, но я подозреваю, что это могло бы решить проблему.

Если у кого-то нет лучшего предложения, я буду придерживаться вызова refresh, который на самом деле, вероятно, в любом случае имеет больше смысла для моего приложения.

1 голос
/ 07 июля 2010

Документы hibernate говорят, что вы можете установить его с помощью свойства hibernate.max_fetch_depth. Значение по умолчанию - 3. Вы можете найти его в «Справочной документации по Hibernate» на стр. 47.

1 голос
/ 05 июля 2010

Это действительно смешно.Один из способов обойти это - запросить объект левого соединения к -> B-> C-> D, что также быстрее, если вы все равно собираетесь перейти к объекту D.Было бы что-то вроде этого.

"from A left join fetch B left join fetch C left join fetch D"

Вы также пытались сделать отношения из C-> D нетерпеливыми?Любопытно, что будет потом ...

...