如何在 JPA JPQL 查询中加入两个实体集合?

Posted

技术标签:

【中文标题】如何在 JPA JPQL 查询中加入两个实体集合?【英文标题】:How to join two collection of an entity in JPA JPQL Query? 【发布时间】:2018-06-07 21:03:41 【问题描述】:

我遇到过这样一种情况,我有一个实体有两个集合,可以说

@Entity
Company

@OneToMany
Collection<Cars>

@OneToMany
Collection<Scooter>

这是我的 jpql

select e from com.net.company e JOIN e.cars cr where cr.carname IN ('BMW');

工作正常返回公司

select e from com.net.company e JOIN e.cars cr JOIN e.scooter where cr.carname IN ('BMW');

不返回任何东西

我知道我的 jpql 是错误的,我认为问题在于我加入它的方式可以帮助我解决这个问题

【问题讨论】:

什么是“JOIN e.scooter”试图实现的目标,当此后不再使用踏板车时?为什么不查看 JPA 提供程序日志并查看为每个查询调用的 SQL?这称为“调试” @DN1 我想加入公司实体的滑板车我可能有也可能没有滑板车的名称列表(可选) 这种加入的唯一效果正是你不想要的:只返回至少拥有一辆滑板车的公司。这是预期的和正常的:这就是内部连接的用途。所以,如果你想接受没有scooter的公司,就留下这个额外的join,没有任何其他作用。我不明白您还想通过该加入实现什么目标。 【参考方案1】:

首先让我对 JPQL 和 SQL 中的查询进行一般性评论:

不要添加任何您不需要的连接。他们只会减慢您的查询速度。 您没有在查询中使用连接的 carsscooter。连接子句的唯一作用是您的查询仅返回与至少 1 个car 和 1 个scooter 关联的companies。但这似乎不是预期的行为。

如果您想让scootercars 实体的连接成为可选,您需要使用LEFT JOIN(但话又说回来:如果您不使用实体,为什么要加入这些实体):

select e from com.net.company e LEFT JOIN e.cars cr LEFT JOIN e.scooter where cr.carname IN ('BMW');

如果您要加入实体以初始化company 实体的关联映射属性,则需要使用JOIN FETCH 子句或LEFT JOIN FETCH 子句:

select e from com.net.company e LEFT JOIN FETCH e.cars cr LEFT JOIN FETCH e.scooter where cr.carname IN ('BMW');

我在这里更详细地解释了JOIN FETCH 子句和其他用于初始化关联的选项:5 ways to initialize lazy relations and when to use them

【讨论】:

以上是关于如何在 JPA JPQL 查询中加入两个实体集合?的主要内容,如果未能解决你的问题,请参考以下文章

JPA 多对多JPQL查询语句怎么写?

如何过滤 JPA/JPQL 中的集合?

是否有 JPA / JPQL 查询来搜索春季作为 JSON 传递的实体子集?

JPA 一个实体中的两个惰性集合 - 如何运行 JPA 查询以获取实体和只有一个集合

JPA JPQL简介

可以在一个 JPQL 查询中传递多个命名实体图?