【发布时间】:2020-11-13 16:08:42
【问题描述】:
我正在尝试构建一个条件查询,并为每个传入过滤器一个谓词“和”连接,例如
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 ...]
所以原因是SampleChildEntity 中的mySet 字段上的@Convert。 Hibernate 看到 Set<String> 类型,但不使用 PluralAttributePath 但 SingularAttributePath 导致问题。如果没有 @Convert 它可以工作,但不能删除转换器。
有什么办法可以做到吗?路径可以创建不同吗?
【问题讨论】: