如何使用JPA Criteria Builder检索一对多关系中的详细信息计数
我有一个一对多的关系,其中一个主实体有两个细节实体。我需要的是为每个主实体获取(计数)相关细节实体的数量 Java实体如下所示:如何使用JPA Criteria Builder检索一对多关系中的详细信息计数,jpa,Jpa,我有一个一对多的关系,其中一个主实体有两个细节实体。我需要的是为每个主实体获取(计数)相关细节实体的数量 Java实体如下所示: @Entity public class Master { private Long id; private String name; @OneToMany(mappedBy = "masterId", fetch = FetchType.LAZY) private Collection<Detail1> detail1Collection
@Entity
public class Master {
private Long id;
private String name;
@OneToMany(mappedBy = "masterId", fetch = FetchType.LAZY)
private Collection<Detail1> detail1Collection;
@OneToMany(mappedBy = "masterId", fetch = FetchType.LAZY)
private Collection<Detail2> detail2Collection;
// ..getters / setters
}
@Entity
public class Detail1 {
private Long id;
private String name;
@JoinColumn(name = "MASTER_ID", referencedColumnName = "ID")
@ManyToOne
private Master masterId;
// ..getters / setters
}
@Entity
public class Detail2 {
private Long id;
private String name;
@JoinColumn(name = "MASTER_ID", referencedColumnName = "ID")
@ManyToOne
private Master masterId;
// ..getters / setters
}
select
(select count(*) from detail1 d1 where d1.master_id=master.id) as cntDetail1,
(select count(*) from detail2 d2 where d2.master_id=master.id) as cntDetail2,
master.ID,
master.NAME
from MASTER master
where master.id=?
JPA准备好的查询看起来像这样,这不是我所表达的,因为count列返回细节计数的笛卡尔乘积
select master0_.ID as col_0_0_, master0_.NAME as col_1_0_, count(detail1col3_.ID) as col_2_0_, count(detail2col4_.ID) as col_3_0_
from MASTER master0_
left outer join DETAIL1 detail1col3_ on master0_.ID=detail1col3_.MASTER_ID
left outer join DETAIL2 detail2col4_ on master0_.ID=detail2col4_.MASTER_ID
where master0_.ID=?
group by master0_.ID, master0_.NAME
以下是我如何使用JPA Criteria API构建查询:
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Master> master = cq.from(Master.class);
Join<Master, Detail1> detail1 = master.join(Master_.detail1Collection, JoinType.LEFT);
Join<Master, Detail2> detail2 = master.join(Master_.detail1Collection, JoinType.LEFT);
cq.select(cb.tuple(master.get(Master_.id), master.get(Master_.name), cb.count(detail1), cb.count(detail2)));
cq.groupBy(master.get(Master_.id), master.get(Master_.name));
cq.where(cb.equal(master.get(Master_.id), master.getId()));
List<Tuple> list = getEntityManager().createQuery(cq).getResultList();
在getEntityManager()中使用此本机SQL查询。createQuery(sqlString)。getResultList()会导致
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: (
将JPA查询更改为以下也会导致“意外令牌”异常
public class MasterDetail {
private long id;
private String name;
private long cntDetail1;
private long cntDetail2;
// ... getter / setter ...
}
public List<> getMasterDetail(long masterId) {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<MasterDetail> cq = cb.createQuery(MasterDetail.class);
final Root<Master> master = cq.from(Master.class);
final Subquery<Detail1> subDetail1 = cq.subquery(Detail1.class);
final Root<Detail1> detail1 = subDetail1.from(subDetail1.getResultType());
final Subquery<Detail2> subDetail2 = cq.subquery(Detail2.class);
final Root<Detail2> detail2 = subDetail2.from(subDetail2.getResultType());
cq.multiselect(
projekt.get(Master_.id),
projekt.get(Master_.name),
projekt.get(Projekt_.bauvorhabenOrt),
cb.count(
subDetail1.select(detail1)
.where(cb.equal(detail1.get(Detail1_.masterId), master.get(Master_.id))))
.alias("cntDetail1"),
cb.count(
subDetail2.select(detail2)
.where(cb.equal(detail2.get(Detail2_.masterId), master.get(Master_.id))))
.alias("cntDetail2")
);
cq.where(cb.equal(master.get(Master_.id), masterId));
List<MasterDetail> results = getEntityManager().createQuery(cq).getResultList();
return results;
}
公共类主细节{
私人长id;
私有字符串名称;
私人长途电话1;
私人长途电话2;
//…getter/setter。。。
}
公共列表getMasterDetail(长masterId){
最终CriteriaBuilder cb=entityManager.getCriteriaBuilder();
最终标准查询cq=cb.createQuery(MasterDetail.class);
最终根主节点=cq.from(主节点类);
最终子查询subDetail1=cq.Subquery(Detail1.class);
最终根detail1=subDetail1.from(subDetail1.getResultType());
最终子查询subDetail2=cq.Subquery(Detail2.class);
最终根detail2=subDetail2.from(subDetail2.getResultType());
多重选择(
项目获取(主项目id),
项目get(主项目名称),
项目get(项目bauvorhabenOrt),
计数(
子详细信息1.选择(详细信息1)
.where(cb.equal(detail1.get(detail1.masterId),master.get(master.id)))
.别名(“CNTDail1”),
计数(
子详细信息2.选择(详细信息2)
.where(cb.equal(detail2.get(detail2.masterId),master.get(master.id)))
.别名(“CNT2”)
);
cq.式中(cb.相等(master.get(master.id),masterId));
列表结果=getEntityManager().createQuery(cq).getResultList();
返回结果;
}
任何提示欢迎-谢谢 好的,您应该使用size(),而不是count():@JBNizet:这不是真的,因为size()会导致编译错误:错误:(208,23)java:找不到适合size(javax.persistence.criteria.Subquery)方法javax.persistence.CriteriaBuilder.size(javax.persistence.criteria.Expression)的方法不适用我没有说在现有查询中只需按大小替换count。我说你必须用它。size()返回集合表达式的大小,Master.detail1Collection是一个集合。在我从数据库检索一个MasterDetail对象的情况下,您是对的。在本例中,我可以这样做:Master Master=getEntityManager().find(Master.class,masterId);MasterDetail md=新的MasterDail();md.setCntDetail1(master.getDetail1Collection().size());md.setCntDetail2(master.getDetail2Collection().size());但是,当我为MasterID执行子选择以检索多个实体时,如何处理它呢?好的,您应该使用size(),而不是count():@JBNizet:这不是真的,因为size()会导致编译错误:error:(208,23)java:找不到适合size的方法(javax.persistence.criteria.Subquery)方法javax.persistence.criteria.CriteriaBuilder.size(javax.persistence.criteria.Expression)不适用我并没有说您必须在现有查询中按大小替换count。我说你必须用它。size()返回集合表达式的大小,Master.detail1Collection是一个集合。在我从数据库检索一个MasterDetail对象的情况下,您是对的。在本例中,我可以这样做:Master Master=getEntityManager().find(Master.class,masterId);MasterDetail md=新的MasterDail();md.setCntDetail1(master.getDetail1Collection().size());md.setCntDetail2(master.getDetail2Collection().size());但是,当我为MasterID执行子选择以检索多个实体时,如何处理它呢?
public class MasterDetail {
private long id;
private String name;
private long cntDetail1;
private long cntDetail2;
// ... getter / setter ...
}
public List<> getMasterDetail(long masterId) {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<MasterDetail> cq = cb.createQuery(MasterDetail.class);
final Root<Master> master = cq.from(Master.class);
final Subquery<Detail1> subDetail1 = cq.subquery(Detail1.class);
final Root<Detail1> detail1 = subDetail1.from(subDetail1.getResultType());
final Subquery<Detail2> subDetail2 = cq.subquery(Detail2.class);
final Root<Detail2> detail2 = subDetail2.from(subDetail2.getResultType());
cq.multiselect(
projekt.get(Master_.id),
projekt.get(Master_.name),
projekt.get(Projekt_.bauvorhabenOrt),
cb.count(
subDetail1.select(detail1)
.where(cb.equal(detail1.get(Detail1_.masterId), master.get(Master_.id))))
.alias("cntDetail1"),
cb.count(
subDetail2.select(detail2)
.where(cb.equal(detail2.get(Detail2_.masterId), master.get(Master_.id))))
.alias("cntDetail2")
);
cq.where(cb.equal(master.get(Master_.id), masterId));
List<MasterDetail> results = getEntityManager().createQuery(cq).getResultList();
return results;
}