Java 使用jpa标准在另一个表中选择每个状态的出现次数

Java 使用jpa标准在另一个表中选择每个状态的出现次数,java,jpa,spring-data-jpa,criteria-api,Java,Jpa,Spring Data Jpa,Criteria Api,我需要在一个查询中使用CriteriaAPI选择我的主表和另一个表中每个状态的出现次数 我目前的解决方案是使用原生查询,这是可行的,但我想用一种更基于对象的方式来实现。 我尝试在criteria中使用特定的查询来选择所有状态,然后手动计数。但通过这种方法,我调用了两个查询:一个用于获取主表中的详细信息,另一个用于选择id与主表相同的所有状态。 有没有更有效的方法 以下是我的本机查询(简化): 这是我的CM实体(简化): 这是我的CM_参数实体(简化): 使用本机查询方法,我可以在我的Cm实体中添

我需要在一个查询中使用CriteriaAPI选择我的主表和另一个表中每个状态的出现次数

我目前的解决方案是使用原生查询,这是可行的,但我想用一种更基于对象的方式来实现。 我尝试在criteria中使用特定的查询来选择所有状态,然后手动计数。但通过这种方法,我调用了两个查询:一个用于获取主表中的详细信息,另一个用于选择id与主表相同的所有状态。 有没有更有效的方法

以下是我的本机查询(简化):

这是我的CM实体(简化):

这是我的CM_参数实体(简化):

使用本机查询方法,我可以在我的Cm实体中添加临时字段:

@Transient
private Long countPending;

@Transient
private Long countFailed;

@Transient
private Long countProcessed;
我如何使用CriteriaAPI,如果可能的话,在一个事务中就可以做到这一点

预期的输出可能是这样的:

{
  "idCm": 1,
  "type": "sms",
  "countPending": 5,
  "countFailed": 3,
  "countProcessed": 9
}

可以在不使用子查询联接的情况下重写查询:

SELECT
    a.id_cm,
    a.type
    COUNT(CASE WHEN b.status = 'PENDING' THEN 1 ELSE NULL END) countPending,
    COUNT(CASE WHEN b.status = 'FAILED' THEN 1 ELSE NULL END) countFailed,
    COUNT( CASE WHEN b.status = 'PROCESSED' THEN 1 ELSE NULL END ) countProcessed
FROM CM AS a
LEFT JOIN CM_PARAM AS b ON a.id_cm = b.id_cm
WHERE a.id_cm = ?1
GROUP BY a.id_cm, a.type
您必须将关联的反面添加到
Cm

@OneToMany(mappedBy = "cm")
private Set<CmParam> params;
请注意,结果的类型为
Object[]
。如果您想使用当前方法处理瞬态字段,最简单的方法是将适当的构造函数添加到
Cm
并使用
cb.construct()
方法:

cq.select(cb.construct(Cm.class, a.get("idCm"), a.get("type"), ...))
请注意:

  • 如果您不想将
    params
    字段添加到
    Cm
    ,但可以使用
    内部连接
    ,您只需使用
    根b=cq.from(CmParam.class)
    连接a=b.JOIN(“Cm”)
  • 如果在实际查询中,您从
    Cm
    中选择的属性多于
    cmId
    status
    ,您可能还需要在
    groupBy
    中列出它们

您的查询可以在不使用子查询联接的情况下重写:

SELECT
    a.id_cm,
    a.type
    COUNT(CASE WHEN b.status = 'PENDING' THEN 1 ELSE NULL END) countPending,
    COUNT(CASE WHEN b.status = 'FAILED' THEN 1 ELSE NULL END) countFailed,
    COUNT( CASE WHEN b.status = 'PROCESSED' THEN 1 ELSE NULL END ) countProcessed
FROM CM AS a
LEFT JOIN CM_PARAM AS b ON a.id_cm = b.id_cm
WHERE a.id_cm = ?1
GROUP BY a.id_cm, a.type
您必须将关联的反面添加到
Cm

@OneToMany(mappedBy = "cm")
private Set<CmParam> params;
请注意,结果的类型为
Object[]
。如果您想使用当前方法处理瞬态字段,最简单的方法是将适当的构造函数添加到
Cm
并使用
cb.construct()
方法:

cq.select(cb.construct(Cm.class, a.get("idCm"), a.get("type"), ...))
请注意:

  • 如果您不想将
    params
    字段添加到
    Cm
    ,但可以使用
    内部连接
    ,您只需使用
    根b=cq.from(CmParam.class)
    连接a=b.JOIN(“Cm”)
  • 如果在实际查询中,您从
    Cm
    中选择的属性多于
    cmId
    status
    ,您可能还需要在
    groupBy
    中列出它们

谢谢!!尤其是查询重写。我不知道为什么我在子查询中选择了艰难的方式。谢谢!!尤其是查询重写。我不知道为什么我在子查询中选择了艰难的方式。
cq.select(cb.construct(Cm.class, a.get("idCm"), a.get("type"), ...))