我有一对多关系,其中一个主实体有两个详细实体。我需要的是为每个主实体获取(计数)相关细节实体的数量。
Java实体如下所示:
@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
}
在纯SQL中,查询如下所示:
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();
SQL Query的第二种方法如下所示,但对于没有DETAIL实体的MASTER实体,这会导致NULL值而不是0:
select detail1Count.cntDetail1, detail2Count.cntDetail2, master.ID as ID, master.NAME
from MASTER master
LEFT JOIN (SELECT master_id, COUNT(*) as cntDetail1 FROM DETAIL1 GROUP BY master_id) detail1Count ON master.id = detail1Count.master_id
LEFT JOIN (SELECT master_id, COUNT(*) as cntDetail2 FROM DETAIL2 GROUP BY master_id) detail2Count ON master.id = detail2Count.master_id
where master.id=?
在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;
}
欢迎任何提示 - 谢谢!