简体   繁体   中英

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

I have an entity named certificate

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

Many certificate can have the same subject and I want to select all certificates that have count of the field subjectId different from 3. I used this code and it worked

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;
}

I tried to do the same thing using a Query-annotated Spring JPA which looks like this:

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

But it doesn't return all the certificates. It returns only certificates by distincts subjectDN.

It looks like the query in your annotation is selecting groups instead of the CertificateData records. One way to get the CertificateData records themselves would be to use a sub-query to find the desired subjectDN values (which is what you already have), and then have the outer query find the records with those subjectDN values. I haven't tested this yet, but in JPQL it would be something like:

@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();

For reference, the SQL (specifically postgres) to do this would be something like:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM