我有许多类作为继承层次结构映射到单个表中。
我想使用以下Criteria
查询,但这会导致ClassCastException
,因为Class
无法投射到 String
.
Set<Class> childClasses = new HashSet<>();
childClasses.add(Child1.class);
childClasses.add(Child2.class);
session.createCriteria(Parent.class)
.add(Restrictions.in("class", childClasses)
.list();
我注意到 Hibernate 确实支持使用 Restrictions.eq("class", childClass)
指定单个类,因此我可以通过使用Disjunction
'来解决问题。我也知道,如果我的重定向基于每个子类的鉴别器字符串,这将起作用,但我不想使用这些字符串。
可以这样使用Criteria
吗?这个问题的公认答案表明,当类是您Criteria
所基于的类的属性时,它有效,但在我上面显示的情况下
查看源代码,我会说这是一个休眠错误。
例如,SimpleExpression
(由 Restrictions.eq
返回)调用criteriaQuery.getTypedValue
,用于处理Class
值到相应鉴别器值的转换。
InExpression
(由 Restrictions.in
返回)按原样添加值,而不进行转换。这就是为什么你会得到ClassCastException
,因为后来尝试将Class
转换为String
(显然你的鉴别器值的类型是String
)。
在修复之前,您可以避免使用此表单(您已经提出了正确的解决方法),或者,如果您真的想坚持直接使用Class
对象,那么您可以在项目中实现自定义InExpression
。例如,类似这样的内容:
public class ClassInExpression extends InExpression {
private static final String CLASS = "class";
private final Collection<Class> values;
public ClassInExpression(Collection<Class> values) {
super(CLASS, values.toArray(new Object[values.size()]));
this.values = values;
}
@Override
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) {
if (criteriaQuery.getTypeUsingProjection(criteria, CLASS).isComponentType()) {
return super.getTypedValues(criteria, criteriaQuery);
}
return convertToDiscriminatorValues(criteria, criteriaQuery);
}
private TypedValue[] convertToDiscriminatorValues(Criteria criteria, CriteriaQuery criteriaQuery) {
List<TypedValue> resultList = new ArrayList<TypedValue>();
for (Object value : values) {
resultList.add(criteriaQuery.getTypedValue(criteria, CLASS, value));
}
return resultList.toArray(new TypedValue[resultList.size()]);
}
}
然后您将使用它而不是Restrictions.in
:
session.createCriteria(Parent.class)
.add(new ClassInExpression(childClasses))
.list()