J'ai les Specification
suivants que j'utilise pour rechercher des entités Contact
liées à certaines entités ManagedApplication
. Je passe un Collection<Long>
Qui contient les identifiants des entités ManagedApplication
que je recherche.
public static Specification<Contact> findByApp(final Collection<Long> appIds) {
return new Specification<Contact>() {
@Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
final Predicate appPredicate = root.join(Contact_.managedApplications)
.get(ManagedApplication_.managedApplicationId).in(appIds);
}
}
}
Je passe cette spécification à la méthode .findAll()
de mon PagingAndSoringRepository
pour récupérer un Page<Contact>
Qui contiendra toutes les entités Contact
qui répondent aux critères de recherche.
Voici le Repository
.
@Repository
public interface PagingAndSortingContactRepository extends PagingAndSortingRepository<Contact, Long>, JpaSpecificationExecutor<Contact> {
}
Et voici comment j'appelle la méthode .findAll()
.
final Page<Contact> contacts = pagingAndSortingContactRepository.findAll(ContactSpecification.findByApp(appIds), pageable);
Cela fonctionne et renvoie toutes les entités Contact
qui sont liées à l'une des entités ManagedApplication
qui correspondent aux identifiants transmis. Cependant, puisque j'appelle .join()
pour rejoindre le Entité Contact
avec l'entité ManagedApplication
, si une Contact
a plusieurs entités ManagedApplication
dans la liste des ID d'application, la requête renverra un doublon Contact
entités.
Donc, ce que je dois savoir, comment puis-je obtenir uniquement des entités Contact
distinctes renvoyées par ma requête en utilisant ce Specification
?
Je sais que CriteriaQuery
a une méthode .distinct()
à laquelle vous pouvez transmettre une valeur booléenne, mais je n'utilise pas l'instance CriteriaQuery
dans toPredicate()
de ma Specification
.
Voici les sections pertinentes de mes métamodèles.
Contact_.Java:
@StaticMetamodel(Contact.class)
public class Contact_ {
public static volatile SingularAttribute<Contact, String> firstNm;
public static volatile SingularAttribute<Contact, String> lastNm;
public static volatile SingularAttribute<Contact, String> emailAddress;
public static volatile SetAttribute<Contact, ManagedApplication> managedApplications;
public static volatile SetAttribute<Contact, ContactToStructure> contactToStructures;
}
ManagedApplication_.Java
@StaticMetamodel(ManagedApplication.class)
public class ManagedApplication_ {
public static volatile SingularAttribute<ManagedApplication, Integer> managedApplicationId;
}
Utilisez le paramètre query
dans votre méthode toPredicate
pour appeler la méthode distincte.
Exemple ci-dessous:
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
final Predicate appPredicate = root.join(Contact_.managedApplications)
.get(ManagedApplication_.managedApplicationId).in(appIds);
query.distinct(true);
...