2016-02-08 2 views
2

У меня есть несколько классов, отображаемых как иерархия наследования в одну таблицу.Может ли запрос на спящий режим для подклассов использовать 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 таким образом? Принятый ответ this question предполагает, что он работает, когда класс является свойством класса, на котором базируется ваш Criteria, но он, похоже, не работает в случае, показанном выше.

ответ

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() 
+0

Спасибо. Я зарегистрировал дефект на https://hibernate.atlassian.net/browse/HHH-10517 – Mark

+0

И дефект был отклонен, так как критерий устарел в Hibernate 5. – Mark

+0

@Mark Я отправил [запрос на извлечение] (https://github.com/hibernate/hibernate-orm/pull/1277), это было принято. Исправление будет доступно как на 5.1, так и на 5.0. –