I have an entity with different fields including an @ElementCollections list:
@Entity
public class Property {
//different attributes
@ElementCollection
@Enumerated(EnumType.STRING)
protected List<PropertyCriteria> criterias = new ArrayList<>();
}
where PropertyCriteria is a simple enum class.
I would like to implement a search method which receive multiple values, and return the correspondent listings.
@GetMapping(value = "/search")
public Page<Property> search(
@RequestParam Map<String, String> filters,
@RequestParam(value = "criterias") List<PropertyCriteria> criterias,
Pageable pageable) {
return service.search(filters, criterias, pageable);
}
In order to do that, it seems to me that specifications is the best way to do it, since I will have others attributes to filter.
The criterias
parameters is a list containing all the values needed in the property(ElementCollections). And the filters Map is a key value parameter with all the others attributes I receive.
I tried something like this, but it doesn't work:
public Page<Property> search(Map<String, String> filters, List<PropertyCriteria> criterias,
Pageable pageable) {
Specification<Property> specification = Specification
.where(criteriasFilter(criterias)
//.and(others specifications on other attributes)
;
return repository.findAll(specification, pageable);
}
public static Specification<Property> criteriasFilter(List<PropertyCriteria> criterias) {
Specification<Property> propertySpecification = (root, query, builder) -> {
query.distinct(true);
Predicate where = builder.conjunction();
return builder.and(where, root.joinList(Property_.CRITERIAS).in(
criterias));
};
return propertySpecification;
}
If you need all criterias to match it's best to create a subquery with a count and check if the count is expected. Something like this:
public static Specification<Property> criteriasFilter(List<PropertyCriteria> criterias) {
Specification<Property> propertySpecification = (root, query, builder) -> {
Subquery<Long> subquery = query.subquery(Long.class);
Root<Property> r = subquery.correlate(root);
subquery.where(r.joinList(Property_.CRITERIAS).in(
criterias));
subquery.select(builder.count(builder.literal(1)));
return builder.equal(subquery, (Long) criterias.size());
};
return propertySpecification;
}