如何使用 JPA Criteria Builder 编写带有附加计数列的查询
How to write query with additional count column using JPA Criteria Builder
我正在努力编写一个 JPA 查询,该查询将 return 数据库中的所有 P 对象,并且在它们旁边我想计算它们的 S 子对象的 propertyA = 1。
SQL查询
Select p.*, (Select count(s.id) 来自 s_table s
其中 p.id = s.p_id 和 s.propertyA = 1) 来自 p_table p
映射:
@Entity
@Table(name = "t_table")
public class PTable{
@Id
private String id;
@Version
private Long version;
private String subject;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "p_id", referencedColumnName = "id")
private Set<STable> sSet = new HashSet<>();
}
@Entity
@Table(name = "s_table")
public class STable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "p_id")
private String pId;
private String propertyA;
}
此外,您是否愿意指出任何在 JPA 中编写复杂查询的好教程。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<PTable> q = cb.createQuery(PTable.class);
Root<PTable> c = q.from(PTable.class);
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<MyPojo> cq = cb.createQuery(MyPojo.class);
Root<PTable> rootPTable = cq.from(PTable.class);
Join<PTable, STable> joinSTable = rootPTable.join(PTable_.sSet);
Subquery<Long> sqCount = cq.subquery(Long.class);
Root<STable> sqRootSTable = sqCount.from(STable.class);
Join<STable, PTable> sqJoinPTable = sqRootSTable.join(STable_.pSet);
sqCount.where(cb.and(
cb.equal(sqJoinPTable.get(PTable_.id),rootPTable.get(PTable_.id)),
cb.equal(sqRootSTable.get(STable_.propertyA),"1")));
sqCount.select(cb.count(sqRootSTable));
cq.multiselect(
rootPTable.get(PTable_.id),
rootPTable.get(PTable_.version),
rootPTable.get(PTable_.subject),
joinSTable.get(STable_.id),
sqCount.getSelection(),
);
您将需要一个 Pojo 来获取构造函数具有的结果,该结果与多选参数的顺序和类型匹配,如下所示:
public MyPojo(String pId, Long version, String subject, Long sId, Long count){
[...]
}
您还必须更改您的实体以正确映射关系,双向和懒惰以提高性能如下:
PTable
@OneToMany(mappedBy="p",fetch = FetchType.LAZY)
private Set<STable> sSet;
表
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="id")
private PTable p;
我正在努力编写一个 JPA 查询,该查询将 return 数据库中的所有 P 对象,并且在它们旁边我想计算它们的 S 子对象的 propertyA = 1。
SQL查询
Select p.*, (Select count(s.id) 来自 s_table s 其中 p.id = s.p_id 和 s.propertyA = 1) 来自 p_table p
映射:
@Entity
@Table(name = "t_table")
public class PTable{
@Id
private String id;
@Version
private Long version;
private String subject;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "p_id", referencedColumnName = "id")
private Set<STable> sSet = new HashSet<>();
}
@Entity
@Table(name = "s_table")
public class STable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "p_id")
private String pId;
private String propertyA;
}
此外,您是否愿意指出任何在 JPA 中编写复杂查询的好教程。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<PTable> q = cb.createQuery(PTable.class);
Root<PTable> c = q.from(PTable.class);
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<MyPojo> cq = cb.createQuery(MyPojo.class);
Root<PTable> rootPTable = cq.from(PTable.class);
Join<PTable, STable> joinSTable = rootPTable.join(PTable_.sSet);
Subquery<Long> sqCount = cq.subquery(Long.class);
Root<STable> sqRootSTable = sqCount.from(STable.class);
Join<STable, PTable> sqJoinPTable = sqRootSTable.join(STable_.pSet);
sqCount.where(cb.and(
cb.equal(sqJoinPTable.get(PTable_.id),rootPTable.get(PTable_.id)),
cb.equal(sqRootSTable.get(STable_.propertyA),"1")));
sqCount.select(cb.count(sqRootSTable));
cq.multiselect(
rootPTable.get(PTable_.id),
rootPTable.get(PTable_.version),
rootPTable.get(PTable_.subject),
joinSTable.get(STable_.id),
sqCount.getSelection(),
);
您将需要一个 Pojo 来获取构造函数具有的结果,该结果与多选参数的顺序和类型匹配,如下所示:
public MyPojo(String pId, Long version, String subject, Long sId, Long count){
[...]
}
您还必须更改您的实体以正确映射关系,双向和懒惰以提高性能如下:
PTable
@OneToMany(mappedBy="p",fetch = FetchType.LAZY)
private Set<STable> sSet;
表
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="id")
private PTable p;