I have the following Specification
that I use to query for any Contact
entities that are tied to certain ManagedApplication
entities. I pass in a Collection<Long>
that contains the ids of the ManagedApplication
entities that I am searching for.
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); } } }
I pass this specification to the .findAll()
method of my PagingAndSoringRepository
to retrieve a Page<Contact>
that will contain all Contact
entities that meet the search criteria.
Here is the Repository
.
@Repository public interface PagingAndSortingContactRepository extends PagingAndSortingRepository<Contact, Long>, JpaSpecificationExecutor<Contact> { }
And here is how I'm calling the .findAll()
method.
final Page<Contact> contacts = pagingAndSortingContactRepository.findAll(ContactSpecification.findByApp(appIds), pageable);
This works and returns all Contact
entities that are tied to any of the ManagedApplication
entities that correspond to the ids passed in. However, since I am calling .join()
to join the Contact
entity with the ManagedApplication
entity, if one Contact
has multiple ManagedApplication
entities in the list of app ids, then the query will return duplicate Contact
entities.
So what I need to know is, how can I get only distinct Contact
entities returned from my query using this Specification
?
I know that CriteriaQuery
has a .distinct()
method that you can pass a boolean value to, but I am not using the CriteriaQuery
instance in the toPredicate()
method of my Specification
.
Here are the relevant sections of my 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; }
First of all, JPA only creates an implicit inner join when we specify a path expression. For example, when we want to select only the Employees that have a Department, and we don't use a path expression like e. department, we should use the JOIN keyword in our query.
SPring Data Jpa Specifications helps us to create dynamic queries based on the requirement at run time. Spring Data Jpa Specifications allows a combination of the attributes or properties of a domain or entity class and creates a query.
You can add the DISTINCT keyword to your query to tell Hibernate to return each Author entity only once. But as you can see in the following log messages, Hibernate also adds the DISTINCT keyword to the SQL query.
Its findById method retrieves an entity by its id. The return value is Optional<T> . Optional<T> is a container object which may or may not contain a non-null value. If a value is present, isPresent returns true and get returns the value.
Use the query
parameter in your toPredicate
method to invoke the distinct method.
Sample below:
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); ...
a new static method could be added
public static Specification<Object> distinct() { return (root, query, cb) -> { query.distinct(true); return null; }; }
where later you could add when creating your Specification
Specification.where( YourStaticClassWhereYouCreatedTheUpperMethod.distinct().and(..))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With