Я пытаюсь создать запрос критериев и для каждого входящего фильтра предикат и связанный, например.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
Root<T> entityRoot = criteriaQuery.from(SampleEntity.class);
// for each filterable field create a Predicate and included in as `criteriaQuery.where(...)`
criteriaQuery.select(criteriaBuilder.count(entityRoot));
entityManager.createQuery(criteriaQuery).setMaxResults(maxResult).getSingleResult();
Для каждого такого фильтра (см. строку с комментариями в примере кода выше) сначала создается путь.
Path<?> path = PathBuilder.buildFromFieldName(fieldName, rootEntity);
Это будет метод:
public static <T> Path<?> buildFromFieldName(String fieldName, Root<T> entity) throws IllegalArgumentException {
Path<?> path = entity;
List<String> fieldNames = Arrays.asList(fieldName.split("\\."));
for (String fieldNamePath : fieldNames) {
path = path.get(fieldNamePath);
}
return path;
}
Вложенные поля появятся, например. с именем myChild.mySet
в следующем примере.
@Entity
@Table(name = "T_SAMPLE")
public class SampleEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Embedded
private SampleChildEntity myChild;
}
@Embeddable
public class SampleChildEntity {
@Convert(converter = CommaSeparatedSetConverter.class, attributeName = "mySet")
private Set<String> mySet = new HashSet<>();
}
Учитывая этот пример, при вызове criteriaBuilder.isMember(filterValue, path)
возникает следующее исключение (filterValue будет значением для сравнения, например, строкой поиска).
Причина: В методе buildFromFieldName
сначала создается путь из корневого объекта (SampleEntity). Тогда он имеет тип org.hibernate.query.criteria.internal.path.RootImpl
. Когда в цикле for обрабатывается fieldNamePath myChild
, Path воссоздается. Затем он имеет тип org.hibernate.query.criteria.internal.path.SingularAttributePath
и остается таким, когда обрабатывается последний fieldNamePath mySet
. Только когда @Convert
удаляется, тип изменяется на org.hibernate.query.criteria.internal.path.PluralAttributePath
, поскольку это тип коллекции.
java.lang.IllegalArgumentException: unknown collection expression type
[org.hibernate.query.criteria.internal.path.SingularAttributePath]
at org.hibernate.query.criteria.internal.CriteriaBuilderImpl.isMember(CriteriaBuilderImpl.java:1324)
[... stack trace contains further local classes ...]
Итак, причина в @Convert
в поле mySet
в файле SampleChildEntity
. Hibernate видит тип Set<String>
, но использует не PluralAttributePath
, а SingularAttributePath
, что вызывает проблему. Без @Convert
работает, но снимать преобразователь не вариант.
Есть ли способ, которым это может работать? Может ли путь быть создан по-другому?