title: How to add distinct property to query with jpa specification
body: <p>I am using jhipster criteria and jpa specification to implement an endpoint for making research.</p>
  
  <p>Well it is working, but keep sending me duplicates.</p>
  
  <p>There is prestations with this model</p>
  
  <pre><code>public class Prestation extends AbstractAuditingEntity implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
  @SequenceGenerator(name = "sequenceGenerator")
  private Long id;
  
  @NotNull
  @Column(name = "jhi_label", nullable = false)
  private String label;
  
  @Column(name = "description")
  private String description;
  
  @Column(name = "unit")
  private String unit;
  
  @NotNull
  @Column(name = "activated", nullable = false)
  private boolean activated;
  
  @ManyToOne(optional = false)
  @NotNull
  @JsonIgnoreProperties("prestations")
  private SubCategory subCategory;
  
  @OneToMany(mappedBy = "prestation", cascade = CascadeType.ALL, orphanRemoval = true)
  private List&lt;CompanyPrestation&gt; companies = new ArrayList&lt;&gt;();
  </code></pre>
  
  <p>And relation between company and prestations</p>
  
  <pre><code>@OneToMany(mappedBy = "company", cascade = CascadeType.ALL, orphanRemoval = true)
  @LazyCollection(LazyCollectionOption.FALSE)
  private List&lt;CompanyPrestation&gt; prestations = new ArrayList&lt;&gt;();
  </code></pre>
  
  <p>And here is the CompanySpecification class that i used to create specification that i give to the repository</p>
  
  <pre><code>public class CompanySpecification extends QueryService&lt;Company&gt; implements Specification&lt;Company&gt; {
  
  private static final long serialVersionUID = 1L;
  private CompanyCriteria criteria;
  
  public CompanySpecification(CompanyCriteria criteria) {
      this.criteria = criteria;
  }
  
  @Override
  public Predicate toPredicate(Root&lt;Company&gt; roots, CriteriaQuery&lt;?&gt; query, CriteriaBuilder builder) {
  
      Specification&lt;Company&gt; specification = Specification.where(null);
      if (criteria != null) {
          if (criteria.getName() != null) {
              specification = specification.or(buildStringSpecification(criteria.getName(), Company_.name));
          }
          if (criteria.getSiret() != null) {
              specification = specification.or(buildStringSpecification(criteria.getSiret(), Company_.siret));
          }
          if (criteria.getCodeAPE() != null) {
              specification = specification.or(buildStringSpecification(criteria.getCodeAPE(), Company_.codeAPE));
          }
          if (criteria.getLegalForm() != null) {
              specification = specification.or(buildStringSpecification(criteria.getLegalForm(), Company_.legalForm));
          }
          if (criteria.getVille() != null) {
              specification = specification
                      .and(buildReferringEntitySpecification(criteria.getVille(), Company_.address, Address_.ville));
          }
          if (criteria.getExercicePlace() != null &amp;&amp; !criteria.getExercicePlace().getIn().isEmpty()) {
              Filter&lt;ExercicePlace&gt; exercicePlaceFilter = new Filter&lt;&gt;();
              exercicePlaceFilter.setIn(criteria.getExercicePlace().getIn().stream().map(ExercicePlace::valueOf)
                      .collect(Collectors.toList()));
              specification = specification.and(buildSpecification(exercicePlaceFilter, Company_.exercicePlace));
          }
          if (criteria.getCodePostal() != null) {
              specification = specification.and(buildReferringEntitySpecification(criteria.getCodePostal(),
                      Company_.address, Address_.codePostal));
          }
          if (criteria.getPrestationsId() != null) {
              specification = specification.and(buildSpecification(criteria.getPrestationsId(),
                      root -&gt; root.join(Company_.prestations, JoinType.LEFT)
                              .join(CompanyPrestation_.prestation, JoinType.LEFT).get(Prestation_.id)));
          }
          if (criteria.getCatId() != null) {
              specification = specification.and(buildSpecification(criteria.getCatId(),
                      root -&gt; root.join(Company_.prestations, JoinType.LEFT)
                              .join(CompanyPrestation_.prestation, JoinType.LEFT)
                              .join(Prestation_.subCategory, JoinType.LEFT).join(SubCategory_.category, JoinType.LEFT)
                              .get(Category_.id)));
          }
          if (criteria.getSubCatId() != null) {
              specification = specification.and(buildSpecification(criteria.getSubCatId(),
                      root -&gt; root.join(Company_.prestations, JoinType.LEFT)
                              .join(CompanyPrestation_.prestation, JoinType.LEFT)
                              .join(Prestation_.subCategory, JoinType.LEFT).get(SubCategory_.id)));
          }
          if (criteria.getPrestationName() != null) {
              specification = specification.or(buildSpecification(criteria.getPrestationName(),
                      root -&gt; root.join(Company_.prestations, JoinType.LEFT)
                              .join(CompanyPrestation_.prestation, JoinType.LEFT).get(Prestation_.label)));
          }
          if (criteria.getPriceMinimum() != null || criteria.getPriceMaximum() != null) {
              specification = specification.and((lroot, lquery, lcriteriaBuilder) -&gt; {
                  ListJoin&lt;Company, CompanyPrestation&gt; joinCompnayToCompanyPrestations = lroot
                          .join(Company_.prestations, JoinType.LEFT);
                  if (criteria.getPriceMinimum() != null &amp;&amp; criteria.getPriceMaximum() != null) {
                      return lcriteriaBuilder.between(
                              joinCompnayToCompanyPrestations.get(CompanyPrestation_.pricePerUnit),
                              criteria.getPriceMinimum().getGreaterOrEqualThan(),
                              criteria.getPriceMaximum().getLessOrEqualThan()
                      );
                  } else if (criteria.getPriceMinimum() != null) {
                      return lcriteriaBuilder.greaterThanOrEqualTo(
                              joinCompnayToCompanyPrestations.get(CompanyPrestation_.pricePerUnit),
                              criteria.getPriceMinimum().getGreaterOrEqualThan());
                  } else {
                      return lcriteriaBuilder.lessThanOrEqualTo(
                              joinCompnayToCompanyPrestations.get(CompanyPrestation_.pricePerUnit),
                              criteria.getPriceMaximum().getLessOrEqualThan());
                  }
              });
          }
      }
      return specification.toPredicate(roots, query, builder);
  }
  </code></pre>
  
  <p>And here is my service method using it</p>
  
  <pre><code>@Transactional(readOnly = true)
  public Page&lt;CompanyDTO&gt; findByCriteria(CompanyCriteria criteria, Pageable page) {
      log.debug("find by criteria : {}, page: {}", criteria, page);
      Specification&lt;Company&gt; spec = Specification.where(null);
      CompanySpecification specification =  new CompanySpecification(criteria);
      spec = (Specification&lt;Company&gt;) specification;
      Page&lt;Company&gt; vitrinesPage = companyRepository.findAll(spec, page);
      List&lt;CompanyDTO&gt; list = companyMapper.toDto(vitrinesPage.getContent());
      Page&lt;CompanyDTO&gt; listPage = new PageImpl&lt;&gt;(list, page, vitrinesPage.getTotalElements());
      return listPage;
  }
  </code></pre>
  
  <p>I found a method distinct in CriteriaQuery but i dont really know how to add it in my specification. </p>
  
  <p>Some help please!</p>