我需要在单个查询中获取一个具有多个子节点层的复杂对象,直到最后一片叶子(最好)。每个父母与他们各自的孩子都有{"Name": "Bob Smith", "Address": "123 main st", "Telephone": "111-111-1111"}
{"Name": "Jon Smith", "Address": "123 main st", "Telephone": "111-111-1111", "extra": ["222-222-2222"]}
关系。
为了实现这一点,我试图在所有@OneToMany
关系上使用FetchType.EAGER
和FetchMode.JOIN
,所以当我获取最顶层的对象时,Hibernate将生成一个包含以下内容的查询:所有的孩子。但是,不幸的是,我遇到了N + 1问题。我相信这是因为我的实体之间的关系形成了“菱形”,就像这样:
当我如图所示映射关系时,Hibernate会生成N + 1个查询。但是,如果我删除与@OneToMany
的两个关系之一,则一切正常,并且Hibernate在单个查询中完成了工作(符合预期)。
以下是重现该问题的一些最小代码:
BOTTOM
还有我用来获取@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
正在生成的SQL如下所示:
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();
有人知道需要更改什么以便Hibernate生成单个查询而不是N + 1吗? 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 = ?
和id
列的这种双重选择可能已经是映射某些基本问题的症状了吗?
顺便说一句,我正在使用Hibernate 5.3.2.Final。
谢谢!
答案 0 :(得分:0)
在父类中使用@OneToMany时(@ManyToOne更好的选择是btw) 您需要使用双向关系。否则,您将拥有多个查询。 因此,添加每个孩子类@ManyToOne,然后让他们进行映射。
例如:
@Entity
@Table(name = "Top")
public class Top {
@Id
String id;
@OneToMany(mappedBy = "top", fetch = FetchType.EAGER)
List<Left> left = new ArrayList<>();
@OneToMany(mappedBy = "top", fetch = FetchType.EAGER)
List<Right> right = new ArrayList<>();
}
@Entity
@Table(name = "Left")
public class Left {
@Id
String id;
String parent;
@ManyToOne
@JoinColumn(name = "top_id")
Top top;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
Set<Bottom> bottom;
}
@Entity
@Table(name = "Right")
public class Right {
@Id
String id;
String parent;
@ManyToOne
@JoinColumn(name = "top_id")
Top top;
@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
Set<Bottom> bottom;
}