问题描述
首先,我创建了一个通用谓词,试图在元素集合中查找任何匹配项。例如。实体:
@Entity
public class Movie {
...
@ElementCollection
private Set<String> genre;
...
}
谓词将与包含[“ action”,“ drama”]所有类型类型中具有“ action”或“ drama”的电影的给定集合匹配。
谓词正在查找以下内容(泛型):
public static <E> Predicate matchStringSetCaseInsensitive(Set<String> set,SetAttribute<E,String> attribute,CriteriaBuilder criteriaBuilder,Root<E> root,boolean isstrict) {
Predicate predicate;
if (!isEmpty(set)) {
List<Predicate> matchEach = new ArrayList<>();
Join<E,String> joinedString = root.join(attribute,JoinType.LEFT);
for (String string : set) {
matchEach.add(criteriaBuilder.equal(criteriaBuilder.lower(joinedString),string.toLowerCase()));
}
if (isstrict) {
//NOT working
predicate = criteriaBuilder.and(matchEach.toArray(new Predicate[] {}));
} else {
predicate = criteriaBuilder.or(matchEach.toArray(new Predicate[] {}));
}
} else {
predicate = criteriaBuilder.isEmpty(root.get(attribute));
}
return predicate;
}
在上述情况下,isstrict设置为false 。
问题是,它不能与isstrict = true
一起使用。如果为true,查询将尝试查找具有与所有给定流派相匹配的流派的条目-这显然行不通。给定“动作”,“戏剧”,它将匹配流派等于“动作”和“戏剧”的条目。
如何进行这项工作?我考虑过使用or并计算不同的结果:
有人可以提供建议以针对目标实体中的ElementCollection创建匹配集合中每个给定项目的谓词吗?
解决方法
我设法创建了一个单独的谓词来匹配给定集合中的所有元素:
public static <E> Predicate matchStringSetContainsAll(Set<String> set,SetAttribute<E,String> attribute,CriteriaBuilder cB,Root<E> root,CriteriaQuery<E> query,boolean strict) {
Predicate predicate;
if (!isEmpty(set)) {
Subquery<Long> subquery = query.subquery(Long.class);
Root<E> subQueryRoot = subquery.correlate(root);
SetJoin<E,String> tagJoin = subQueryRoot.join(attribute);
Predicate[] match = set.stream().map(tag -> cB.equal(cB.lower(tagJoin),tag.toLowerCase()))
.toArray(Predicate[]::new);
Predicate tagMatch = cB.or(match);
subquery.select(cB.count(tagJoin)).where(tagMatch);
Predicate matchAll = cB.equal(subquery,set.size());
Predicate strictP = cB.and();
if (strict) {
Subquery<Long> countAll = query.subquery(Long.class);
Root<E> countAllRoot = countAll.correlate(root);
SetJoin<E,String> join = countAllRoot.join(attribute);
countAll.select(cB.count(join));
strictP = cB.equal(countAll,set.size());
}
predicate = cB.and(matchAll,strictP);
} else {
predicate = cB.isEmpty(root.get(attribute));
}
return predicate;
}
如果strict==true
仅在目标属性的条目数不超过给定值时匹配。
方法是在此处建议的子选择中使用count: Finding items with a set containing all elements of a given set with jpql
(第二个答案两次否定in
无效)