ManyToOne上的JPA Criteria API可选关系

时间:2017-08-24 03:34:11

标签: java hibernate jpa

我正在尝试使用以下结构上的JPA Criteria API进行简单查询

1)员工

    public class Employee {

        @Id
        @Column(name = "ID", length = 64)
        private String id;

        @Column(name = "NAME", length = 512)
        private String name;

        @ManyToOne(optional = true)
        @JoinColumn(name = "ORG_ID", nullable = true)
        private InternalOrg organization;

    }

2)InternalOrg

    public class InternalOrg {

        @Id
        @Column(name = "ID", length = 64)
        private String id;

        @Column(name = "ORGANIZATION", length = 512)
        private String organization;

        @Column(name = "CODE", length = 64)
        private String code;

    }

3)查询

    EntityManager em = getEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
    Root<Employee> emp = cq.from(Employee.class);

    cq.where(cb.or(emp.get(Employee_.organization).isNull(),
            cb.equal(emp.get(Employee_.organization).get(InternalOrg_.code), "1")));

    return em.createQuery(cq).getResultList();

正如您所见,Employee上的“organization”属性是可选的。我正在尝试做的是使用条件API的查询,该API返回“employee.organization”为NULL或“employee.organization.code”等于参数的所有记录。我该怎么办?

我做了一些测试并意识到如果我改变了这个:

    cq.where(cb.or(emp.get(Employee_.organization).isNull(),
            cb.equal(emp.get(Employee_.organization).get(InternalOrg_.code), "1")));

对此:

 cq.where(cb.or(emp.get(Employee_.organization).isNull()));

它可以工作但只返回组织为NULL的记录。

如果我改为:

cq.where(cb.equal(emp.get(Employee_.organization).get(InternalOrg_.code), "1"));

忽略employee.organization为NULL的记录。

如何返回组织满足条件的员工以及组织为空的员工?

提前致谢,

2 个答案:

答案 0 :(得分:1)

终于找到了解决方案。

创建获得所需结果的唯一方法是先获取(JoinType.LEFT)关系,这是最终的条件查询:

    EntityManager em = getEntityManager();
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
    Root<Employee> emp = cq.from(Employee.class);

    emp.fetch(Employee_.domain, JoinType.LEFT);

    cq.where(cb.or(emp.get(Employee_.organization).isNull(),
            cb.equal(emp.get(Employee_.organization).get(InternalOrg_.code), "1")));

    return em.createQuery(cq).getResultList();

感谢您的支持!

答案 1 :(得分:0)

通过调用CriteriaQuery.where方法设置的条件可以限制CriteriaQuery对象上的查询结果。调用where方法类似于在JPQL查询中设置WHERE子句。

示例:

EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();    
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
    Root<Employee> emp = cq.from(Employee.class);
    cq.where(emp.get(Employee_.organization).isNull());

要指定多个条件谓词,请使用CriteriaBuilder接口的复合谓词方法(和/或/不)。

cq.where(emp.get(Employee_.organization).isNull())
.or(cb.eq(emp.get(Employee_.organization.code), "ABC"));

<强>更新

试试这个:

cq.where(
  cb.or(
    cb.isNull(emp.get(Employee_.organization)),
    cb.equal(emp.get(Employee_.organization).get(InternalOrg_.code), "1")));