Мне нужно извлечь сложный объект с несколькими слоями подузлов до самого последнего листа (предпочтительно) в одном запросе. Каждый родитель имеет отношение @OneToMany
к своим соответствующим детям.
Чтобы достичь этого, я пытался использовать FetchType.EAGER
и FetchMode.JOIN
для всех отношений @OneToMany
, поэтому, когда я выбираю самый верхний объект, Hibernate генерирует один запрос, содержащий все дочерние элементы. Однако, к сожалению, я сталкиваюсь с проблемой N + 1. Я считаю, что это происходит потому, что отношения между моими сущностями образуют «ромбовидную форму», например:
Когда я отображаю отношения, как показано на рисунке, Hibernate генерирует N + 1 запросов. Однако если я удалю одно из двух отношений к BOTTOM
, то все будет работать нормально, и Hibernate выполнит работу в одном запросе (как и ожидалось).
Вот минимальный код для воспроизведения проблемы:
@Entity
@Table(name = "Top")
public class Top {
@Id
String id;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
@Fetch(value = FetchMode.JOIN)
Set<Left> left;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
@Fetch(value = FetchMode.JOIN)
Set<Right> right;
}
@Entity
@Table(name = "Left")
public class Left {
@Id
String id;
String parent;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
@Fetch(value = FetchMode.JOIN)
Set<Bottom> bottom;
}
@Entity
@Table(name = "Right")
public class Right {
@Id
String id;
String parent;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
@Fetch(value = FetchMode.JOIN)
Set<Bottom> bottom;
}
@Entity
@Table(name = "Bottom")
public class Bottom{
@Id
String id;
String parent;
}
И код, который я использую для извлечения объекта TOP
:
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
//Some arbitrary known "Top" object
session.get(Top.class, "1");
session.getTransaction().commit();
session.close();
Генерируемый SQL выглядит следующим образом:
SELECT top0_.id AS id1_3_0_,
left1_.parent AS parent2_1_1_,
left1_.id AS id1_1_1_,
left1_.id AS id1_1_2_,
left1_.parent AS parent2_1_2_,
bottom2_.parent AS parent2_0_3_,
bottom2_.id AS id1_0_3_,
bottom2_.id AS id1_0_4_,
bottom2_.parent AS parent2_0_4_,
right3_.parent AS parent2_2_5_,
right3_.id AS id1_2_5_,
right3_.id AS id1_2_6_,
right3_.parent AS parent2_2_6_
FROM Top top0_
LEFT OUTER JOIN Left left1_
ON top0_.id = left1_.parent
LEFT OUTER JOIN Bottom bottom2_
ON left1_.id = bottom2_.parent
LEFT OUTER JOIN Right right3_
ON top0_.id = right3_.parent
WHERE top0_.id = ?
SELECT bottom0_.parent AS parent2_0_0_,
bottom0_.id AS id1_0_0_,
bottom0_.id AS id1_0_1_,
bottom0_.parent AS parent2_0_1_
FROM Bottom bottom0_
WHERE bottom0_.parent = ?
Кто-нибудь знает, что нужно изменить, чтобы Hibernate генерировал один запрос вместо N + 1? Возможно, этот двойной выбор столбцов id
и parent
уже является признаком некоторой основной проблемы с отображением?
Кстати, я использую Hibernate 5.3.2.Final.
Заранее спасибо!