【问题标题】:Can Hibernate Criteria query for subclasses using Restrictions.in?Hibernate Criteria 可以使用 Restrictions.in 查询子类吗?
【发布时间】:2016-02-08 14:37:30
【问题描述】:

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

我想使用以下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吗?对this question 的公认答案表明,当该类是您的Criteria 所基于的类的属性时它可以工作,但在我上面显示的情况下它似乎不起作用。

【问题讨论】:

    标签: java hibernate


    【解决方案1】:

    查看源代码,我会说这是一个 Hibernate 错误。

    例如,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()
    

    【讨论】:

    • 并且该缺陷被拒绝,因为在 Hibernate 5 中不推荐使用 Criteria。
    • @Mark 我提交了pull request,已经被接受。该修复将在 5.1 和 5.0 上可用。
    • 谢谢。我现在使用 4.3 和上面的代码,但很高兴知道如果/当我们移动到 5.x 时它会开箱即用
    猜你喜欢
    • 2011-10-28
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 2021-02-03
    • 2012-02-15
    • 2019-04-01
    • 2017-08-14
    相关资源
    最近更新 更多