【发布时间】:2021-05-26 02:15:12
【问题描述】:
我有一个生产项目,它使用非常旧的 Ebean ORM(来自 Play Framework)。 Out 团队决定寻求迁移到更新的工具。 在我们的代码中,我们有很多 ORM 模型,并且通常有巨大的实体图(在一个“嵌套级别”中最多 20 个 OneToMany 关系,每个嵌套最多 3 层,这是很多关系,即应该急切地获取以避免 N+1 问题)。 我们当前的框架允许我们编写非常简洁的代码来获取 OneToMany 关系,假设示例:
@Entity
public class A {
@OneToMany
private List<B> bs;
@OneToMany
private List<C> cs;
}
查询代码:
Ebean.find(A.class)
.fetch("bs", new FetchConfig().query())
.fetch("cs", new FetchConfig().query())
... etc
该代码将产生 3 个数据库查询 - 一个用于 A 类,两个用于关系;然后 Ebean 会自动组合这些查询的结果。
我尝试使用 JPA Criteria API 和 NamedEntityGraphs 在 Hibernate ORM 中生成这种代码,但未能成功 - 似乎 Hibernate 不喜欢一次获取多个 OneToMany 关系(通过生成类似 MultipleBagFetchException 的东西) .我了解为什么会引发此异常(笛卡尔积),但我找不到可以在多个数据库查询中拆分一个实体图的框架部分。
可以在 Hibernate 中进行吗?如果没有,是否有任何第三方依赖项,可以这样做吗? Hibernate 用户如何处理大实体图?
【问题讨论】:
-
我在尝试解决这个问题时确实发现了这个 SO 问题 - 不幸的是,手动执行 N 个查询似乎并不方便 - 我特意提到我们有巨大的实体图,手动管理它们会很麻烦.我认为这个问题有一个通用的解决方案,不是吗?如果没有这样的解决方案 - 那么我会关闭这个问题。无论如何,谢谢您的回答。
-
您可以简单地将
List类型替换为Set类型,它会起作用,但会导致笛卡尔积问题。见this question。 -
我明白了。我在我的问题中也提到了这一点。问题是关于 Ebean 功能的任何替代方案,它可以通过不止一个查询来急切地获取所有需要的数据。使用
Set而不是List不会进行多次数据库查询;而 Ebean 会。 -
这是 JPQL 的一个基本限制,也是最初创建 Ebean 的关键原因之一。 hibernate 不仅倾向于生成笛卡尔积,而且它也不支持 SQL 中的 maxRows,因此分页发生在客户端上。这两个都是 JPQL 的设计限制。 JPA(和 Hibernate)只是通过引入 FetchGroup 才开始解决这个限制,这有点接近我们在 Ebean 中所拥有的,但 Ebean 给了我们更多的控制权(获取、获取查询、获取缓存、获取惰性)。注意:我是 Ebean 的创建者。