使用 criteriabuilder.construct 且关系不存在的条件 API 查询
Crieria API query using criteriabuilder.construct with a non existing relationship
给定这个非常简单的 DTO:
@Entity
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
@OneToOne
private Employee boss;
}
我想进行一个查询以收集所有员工姓名及其老板的 ID,放入一个干净整洁的 POJO:
public class EmployeeInfo {
private String name;
private Long bossId;
public EmployeeInfo(String name, Long bossId) {
this.name = name;
this.bossId = bossId;
}
}
这个查询应该有用:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<EmployeeInfo> query = cb.createQuery(EmployeeInfo.class);
Root<Employee> root = query.from(Employee.class);
query.select(
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
root.get("boss").get("id").as(Long.class)));
result = em.createQuery(query).getResultList();
当 employee 列中出现 bossId 时,这就很好用了。但是当没有设置 boss id 时,该记录将被完全忽略。那么对于 construct/multiselect,我如何将这个不存在的老板关系视为 null 或 0?
在纯 SQL 中很容易:
SELECT name, COALESCE(boss_id, 0) FROM EMPLOYEE;
但看在上帝的份上,我不能让标准 api 做到这一点。
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
cb.coalesce(root.get("boss").get("id").as(Long.class), 0L)));
问题是 root.get("boss")
像这样 from Employee employee, Employee boss where employee.boss.id=boss.id
使用交叉连接生成查询。因此忽略 employee.boss.id is null
的记录。
要解决问题,您应该使用 root.join("boss", JoinType.LEFT)
而不是 root.get("boss")
给定这个非常简单的 DTO:
@Entity
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
@OneToOne
private Employee boss;
}
我想进行一个查询以收集所有员工姓名及其老板的 ID,放入一个干净整洁的 POJO:
public class EmployeeInfo {
private String name;
private Long bossId;
public EmployeeInfo(String name, Long bossId) {
this.name = name;
this.bossId = bossId;
}
}
这个查询应该有用:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<EmployeeInfo> query = cb.createQuery(EmployeeInfo.class);
Root<Employee> root = query.from(Employee.class);
query.select(
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
root.get("boss").get("id").as(Long.class)));
result = em.createQuery(query).getResultList();
当 employee 列中出现 bossId 时,这就很好用了。但是当没有设置 boss id 时,该记录将被完全忽略。那么对于 construct/multiselect,我如何将这个不存在的老板关系视为 null 或 0?
在纯 SQL 中很容易:
SELECT name, COALESCE(boss_id, 0) FROM EMPLOYEE;
但看在上帝的份上,我不能让标准 api 做到这一点。
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
cb.coalesce(root.get("boss").get("id").as(Long.class), 0L)));
问题是 root.get("boss")
像这样 from Employee employee, Employee boss where employee.boss.id=boss.id
使用交叉连接生成查询。因此忽略 employee.boss.id is null
的记录。
要解决问题,您应该使用 root.join("boss", JoinType.LEFT)
而不是 root.get("boss")