休眠条件可以使用 Restrictions.in 查询子类吗?



我有许多类作为继承层次结构映射到单个表中。

我想使用以下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()

最新更新