java - 使用 JPA CriteriaBuilder 生成查询,其中属性位于列表中或为空

标签 java jpa eclipselink criteria-api

我正在尝试使用 JPA CriteriaBuilder 为名为“TestContact”的实体生成查询,该实体与另一个名为“SystemGroup”的实体进行多对多联接,其中该联接的属性称为“groups”。该查询的目标是从“TestContact”实体中检索记录,其中“groups”属性位于列表中或为空。

我使用的代码如下

public List<TestContact> findWithCriteriaQuery(List<SystemGroup> groups) {

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<TestContact> cq = cb.createQuery(TestContact.class);
    Root<TestContact> testContact = cq.from(TestContact.class);
    cq.select(testContact);

    Path<List<SystemGroup>> groupPath = testContact.get("groups");

    // cq.where(groupPath.in(groups));
    // cq.where(cb.isEmpty(groupPath));
    cq.where(cb.or(cb.isEmpty(groupPath), groupPath.in(groups)));

    TypedQuery<TestContact> tq = em.createQuery(cq);

    return tq.getResultList();
}

问题是此查询仅返回组位于列表“组”中的结果,但由于某种原因也不会返回组为空的结果(即连接表中没有条目)

如果我将 where 子句更改为 cq.where(cb.isEmpty(groupPath));那么查询正确返回组为空的结果。

如果我将 where 子句更改为 cq.where(groupPath.in(groups));那么查询会正确返回该组位于列表“groups”中的结果。

我不明白的是,为什么当我尝试使用 CriteriaBuilder 或方法组合这两个谓词时,结果不包含该组位于列表中或为空的记录。

“TestContact”实体中的 groups 属性声明如下

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name = "TEST_CONTACT_GROUPS", joinColumns = { @JoinColumn(name = "CONTACT_ID", referencedColumnName = "CONTACT_ID") }, inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", referencedColumnName = "GROUP_ID") })
private List<SystemGroup> groups;

JPA 提供程序是 EclipseLink 2.5.0,Java EE 应用服务器是 GlassFish 4,数据库是 Oracle 11gR2。

谁能指出我哪里错了?

更新

我已经尝试了 @Chris 的建议,但 Eclipse 在 Join<List<SystemGroup>> groupPath = testContact.join("groups", JoinType.LEFT) 上返回以下错误

Incorrect number of arguments for type Join; it cannot be parameterized with arguments >

查看 JavaDoc 中的 Join它说类型参数是...

Z - the source type of the join, X - the target type of the join

我已经尝试过Join<TestContact, SystemGroup> groupPath = testContact.join("groups", JoinType.LEFT);这会导致 Eclipse 在 cb.isEmpty 上返回以下错误

Bound mismatch: The generic method isEmpty(Expression) of type CriteriaBuilder is not applicable for the arguments (Join). The inferred type SystemGroup is not a valid substitute for the bounded parameter >

最佳答案

testContact.get("groups");子句强制从 testContact 到组进行内部联接,这会过滤掉没有组的 testContact。您需要指定左外连接,并在 isEmpty 和 in 子句中使用它。

Root<TestContact> testContact = cq.from(TestContact.class);
cq.select(testContact);

Join<TestContact, SystemGroup> groupPath = testContact.join("groups", JoinType.LEFT);
cq.where(cb.or(cb.isEmpty(testContact.get("groups")), groupPath.in(groups)));

我通常引用https://en.wikibooks.org/wiki/Java_Persistence/Criteria#Join例如

关于java - 使用 JPA CriteriaBuilder 生成查询,其中属性位于列表中或为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25554920/

相关文章:

java - JPA 查询调用 getter 数百万次

java - jpa和eclipselink的jndi数据库连接

Java正则表达式用于删除除小数点外的非数字字符

java - 使用 Play 寻找多对多实体交集的优雅方式

Java:Morphia 用新字段值更新集合有多容易

java - 使用连接表的 Hibernate 一对一单向映射

java - 退出 Activity 时如何在 Firestore 中执行 delete() 操作?

mysql - springboot mysql + jpa 通信链接失败

java - 以编程方式创建实体管理器,无需持久性文件

java - 如何使用EclipseLink为公共(public)接口(interface)下的独立实体声明接口(interface)描述符?