Select 个字段的出现次数不同于使用 spring jpa 的实体

Select entities that have a field with occurence different from using spring jpa

我有一个名为证书的实体

@Entity
public class CertificateData {
    @Id private String id;
    private long expireDate;
    private long createDate;
    private int status;
    private String subjectDN;
...
}

许多证书可以有相同的主题,我想 select 所有 subjectId 字段计数不同于 3 的证书。我使用了这段代码并且有效

public List<CertificateData> findAllByRedundancy() {
    Map<String, Integer> subjectDNCount = new HashMap<>();
    Map<String, List<CertificateData>> subjectDNCertificates = new HashMap<>();

    List<CertificateDto> certificateDataList =
       this.certificaterepository
       .findAll().forEach(certificateData -> {
          String subject = certificateData.getSubjectDN();
          if(subjectDNCount.containsKey(subject)){
              subjectDNCount.put(subject, subjectDNCount.get(subject)+1);
              subjectDNCertificates.get(subject).add(certificateData);
          }
          else{
              subjectDNCount.put(subject, 1);
              subjectDNCertificates.put(subject, new ArrayList<>());
              subjectDNCertificates.get(subject).add(certificateData);
         }
  });
  List<CertificateDto> result = new ArrayList<>();
  subjectDNCount.forEach((s, i) -> {
     if(i!=3){
        result.addAll(subjectDNCertificates.get(s));
  }
  });

  return result;
}

我尝试使用带有查询注释的 Spring JPA 来做同样的事情,它看起来像这样:

@Query("select c from CertificateData c group by c.subjectDN Having count(c) <> 3")
List<CertificateData> findAllByRedundancy();

但它并不是 return 所有的证书。它 return 只有不同主题 DN 的证书。

您注释中的查询似乎是选择组而不是 CertificateData 记录。获取 CertificateData 记录本身的一种方法是使用子查询来查找所需的 subjectDN 值(这是您已经拥有的值),然后让外部查询找到包含这些值的记录subjectDN 个值。我还没有测试过这个,但在 JPQL 中它会是这样的:

@Query(
        "select c from CertificateData c where c.subjectDN in " +
        "(" +
        "   select c.subjectDN from CertificateData c " +
        "   group by c.subjectDN having count(c) <> 3" +
        ")"
)
List<CertificateData> findAllByRedundancy();

作为参考,执行此操作的 SQL(特别是 postgres)类似于:

select * from certificate_data where subject_dn in 
(
    select subject_dn from certificate_data 
    group by subject_dn having count(*) <> 3
)