2015-10-08 22 views
6

Ho il seguente Specification che utilizzo per richiedere qualsiasi entità Contact legata a determinate entità ManagedApplication. Passo in uno Collection<Long> che contiene gli ID delle entità ManagedApplication che sto cercando.Risultati distinti da Dati Spring Data Specifica che utilizza join

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

mi passano questa specifica al metodo della mia PagingAndSoringRepository.findAll() per recuperare un Page<Contact> che conterrà tutti i Contact entità che soddisfano i criteri di ricerca.

Questo è il Repository.

@Repository 
public interface PagingAndSortingContactRepository extends PagingAndSortingRepository<Contact, Long>, JpaSpecificationExecutor<Contact> {  
} 

Ed ecco come lo chiamo il metodo .findAll().

final Page<Contact> contacts = pagingAndSortingContactRepository.findAll(ContactSpecification.findByApp(appIds), pageable); 

funziona e restituisce tutti Contact le entità che sono legati ad uno qualsiasi degli ManagedApplication entità che corrispondono agli ID passati. Tuttavia, dal momento che sto chiamando .join() di aderire al soggetto Contact con l'entità ManagedApplication, se uno Contact ha più entità ManagedApplication nell'elenco degli ID app, quindi la query restituirà le entità duplicate Contact.

Quindi, quello che devo sapere è, come posso ottenere solo le entità distinte Contact restituite dalla mia query utilizzando questo Specification?

so che CriteriaQuery ha un metodo .distinct() che è possibile passare un valore booleano, ma non sto usando l'istanza CriteriaQuery nel metodo della mia SpecificationtoPredicate().

Ecco le sezioni pertinenti dei miei metamodelli.

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

risposta

20

Utilizzare il parametro query nel metodo toPredicate per richiamare il metodo distinto.

esempio riportato di seguito:

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); 
    ... 
+0

Sì, funziona! –

+0

Grazie per questa soluzione, funziona benissimo! Inoltre, per chiarire, è necessario aggiungere 'query.distinct (true)' a ogni predicato che richiede questa distinta dichiarazione. Non è sufficiente aggiungere questa dichiarazione a qualsiasi predicato e farlo funzionare per l'intera query .. –