Dababi
Dababi

Reputation: 185

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.

Upvotes: 0

Views: 169

Answers (1)

Thomas Portwood
Thomas Portwood

Reputation: 1081

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
)

Upvotes: 1

Related Questions