首页 > 解决方案 > JPQL 查询:属于多个类别的项目

问题描述

有一个实体Items有一个名为categories的集合字段,我需要找到至少属于两个特定类别的项目,但我找不到构建正确 JPQL 查询的方法。

@Entity
public class Items {
@ManyToMany (fetch = FetchType.EAGER)
private List<Category> categories;
}

我可以找到具有一个类别的项目:

SELECT i FROM Item i WHERE :cat MEMBER OF item.categories

我可以选择几个类别中的任何一个:

SELECT i FROM Item i WHERE :cat1 MEMBER OF item.categories OR :cat MEMBER OF item.categories

但是,当我尝试选择至少具有两个特定类别的项目时,以下查询不会获得任何项目:

SELECT i FROM Item i WHERE :cat1 MEMBER OF item.categories AND :cat2 MEMBER OF item.categories

哪种方法是正确的?

最好的问候,巴勃罗。

标签: jpamany-to-manyjpql

解决方案


这个问题发生在我的 ObjectDB 身上。我也联系过他们,答案是:

这似乎是 JPQL 查询在执行之前如何转换为类似 SQL 的语法的结果。MEMBER OF 是使用 JOIN 和一个新的合成变量来实现的,用于对集合进行迭代。在您的查询中 item.categories 出现两次,但用于迭代该集合的相同合成变量用于两次出现,并且该变量不能将 AND 的两侧与相同的值匹配。

可能我们可能不得不对每个 MEMBER OF 使用单独的迭代,因为您的帖子所证明的结果似乎是不可接受的(尽管由于转换为 JOIN,JQPL 本身在某些已知情况下具有奇怪的行为)。但是,使用单独的变量有时可能会使查询更加复杂和不必要地变慢(例如,对于您帖子中的 OR 查询),因此任何更改都需要仔细规划。

作为一种快速的解决方案,您可以用 2 个显式 JOIN 变量替换 MEMBER OF 的 AND,以便使用 2 个自变量对集合进行迭代。

因此,解决方案是使用以下查询:

SELECT DISTINCT item
FROM Item item JOIN item.categories cat1 JOIN item.categories cat2
WHERE cat1 = :cat1 AND cat2 = :cat2

我不知道这是否仅适用于这个特定的 JPA 实现(ObjectDB)。无论如何,如果有人有类似的问题,我希望这篇文章可以提供帮助。


推荐阅读