I'm having trouble trying to get a working Specification for this query. My data model looks something like this:
Item {
Person person,
Place place
}
Person {
Address address
}
Place {
Address address
}
Address {
String country
String state
}
An item can have either a Person or a Place associated with it, but not both. I want to query a list of Items based on if their Address matches either an associated Person or Place's address by searching against country AND state. My current implementation looks something like this:
public static Specification<Item> locationIs(String country, String state) {
return (root, query, criteriaBuilder) -> {
Expression<String> personCountry = root.get("person").get("address").get("country");
Expression<String> placeCountry = root.get("place").get("address").get("country");
Expression<String> personState = root.get("person").get("address").get("state");
Expression<String> placeState = root.get("place").get("address").get("state");
Predicate personCountryMatch = criteriaBuilder.like(personCountry, "%" + country + "%");
Predicate personStateMatch = criteriaBuilder.like(personState, "%" + state + "%");
Predicate personMatch = criteriaBuilder.and(personCountryMatch, personStateMatch);
Predicate placeCountryMatch = criteriaBuilder.like(placeCountry, "%" + country + "%");
Predicate placeStateMatch = criteriaBuilder.like(placeState, "%" + state + "%");
Predicate placeMatch = criteriaBuilder.and(placeCountryMatch, placeStateMatch);
Predicate match = criteriaBuilder.or(personMatch, placeMatch);
return match
};
}
If I return just personMatch or just placeMatch it appears to work perfectly for searching on that, but as soon as I try to or them together the whole query returns no results. I've tried creating Specifications from each predicate and combining them that way using, same result.
Ended up just using subqueries for this instead, did something like
criteriaBuilder.or(criteriaBuilder.exists(subquery1), criteriaBuilder.exists(subquery2))
And that worked fine
While subqueries can be a good alternative, the query you seemed to be aiming for originally would have been:
Join<Person> person = root.join("person", JoinType.LEFT);
Join<Person> place = root.join("place", JoinType.LEFT);
Predicate personCountryMatch = criteriaBuilder.like(person.get("country"), "%" + country + "%");
Predicate personStateMatch = criteriaBuilder.like(person.get("state"), "%" + state + "%");
Predicate personMatch = criteriaBuilder.and(personCountryMatch, personStateMatch);
Predicate placeCountryMatch = criteriaBuilder.like(place.get("country"), "%" + country + "%");
Predicate placeStateMatch = criteriaBuilder.like(lace.get("state"), "%" + state + "%");
Predicate placeMatch = criteriaBuilder.and(placeCountryMatch, placeStateMatch);
Predicate match = criteriaBuilder.or(personMatch, placeMatch);
return match
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.