Distintos resultados a partir de la Primavera de Datos de la Especificación JPA que utiliza unirse

Tengo el siguiente Specification que yo uso para consulta de cualquier Contact entidades que están vinculadas a ciertos ManagedApplication entidades. Me paso en un Collection<Long> que contiene los identificadores de los ManagedApplication entidades que estoy buscando.

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

De pasar esta especificación a la .findAll() método de mi PagingAndSoringRepository para recuperar un Page<Contact> que contendrá todos los Contact entidades que cumplen los criterios de búsqueda.

Aquí es el Repository.

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

Y aquí es cómo voy a llamar a la .findAll() método.

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

Esto funciona y devuelve todos los Contact entidades que están vinculadas a ninguna de las ManagedApplication entidades que corresponden a los identificadores que se ha pasado. Sin embargo, desde que yo estoy llamando .join() para unirse a la Contact entidad con la ManagedApplication entidad, si uno Contact tiene múltiples ManagedApplication entidades en la lista de los id de aplicación, a continuación, la consulta devolverá el duplicado Contact entidades.

Así que lo que necesito saber es, ¿cómo puedo obtener sólo distintos Contact entidades de regresar de mi consulta mediante este Specification?

Sé que CriteriaQuery tiene un .distinct() método que puede pasar un valor booleano, pero no estoy utilizando el CriteriaQuery instancia en la toPredicate() método de mi Specification.

Aquí están las secciones pertinentes de mi metamodels.

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

OriginalEl autor Andrew Mairose | 2015-10-08

1 Kommentar

  1. 35

    Utilizar el query parámetro en su toPredicate método para invocar las distintas método.

    Muestra a continuación:

    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);
        ...
    Sí, funciona!
    Gracias por esta solución, funciona muy bien! También, para aclarar, usted tiene que agregar el query.distinct(true) para cada predicado que necesita este distinta declaración. No es suficiente sólo con añadir esta declaración a cualquier predicado y tener un trabajo para toda la consulta..

    OriginalEl autor Ish

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein