关于ManyToOne可选关系的JPA Criteria API

Emi*_*aki 5 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;

    }
Run Code Online (Sandbox Code Playgroud)

2)内部组织

    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;

    }
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

如您所见,Employee的“ organization”属性是可选的。我想做的是使用条件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")));
Run Code Online (Sandbox Code Playgroud)

对此:

 cq.where(cb.or(emp.get(Employee_.organization).isNull()));
Run Code Online (Sandbox Code Playgroud)

它有效,但仅返回组织为NULL的记录。

如果我更改为:

cq.where(cb.equal(emp.get(Employee_.organization).get(InternalOrg_.code), "1"));
Run Code Online (Sandbox Code Playgroud)

employee.organization为NULL的记录将被忽略。

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

提前致谢,

Emi*_*aki 6

终于找到了解决办法。

创建获得所需结果的唯一方法是提前获取 (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();
Run Code Online (Sandbox Code Playgroud)

谢谢你的支持!