Hibernate createCriteria на интерфейсе вызывает N запросов, а не 1 - PullRequest
2 голосов
/ 22 ноября 2011

Моя ситуация такова:

У нас есть суперкласс "MyAbstractEntity"

@Entity
@Table(name = "MyTable")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("FOO")
public abstract class MyAbstractEntity implements Comparable<MyAbstractEntity> {

Этот класс, в свою очередь, имеет довольно много подклассов, выглядящих так:

@Entity
@DiscriminatorValue("BAR")
public class MyEntity extends MyAbstractEntity implements MyInterface {

Около половины подклассов реализуют "MyInterface".

У меня есть Критерии, в которых мне интересно получать только объекты из класса, реализующего этот интерфейс. Когда я определяю свои критерии следующим образом:

Criteria criteria = getSession().createCriteria(MyInterface.class)

Hibernate поворачивается и генерирует один DB-вызов для каждой реализации интерфейса, и DB-парни сходят с ума. Я наполовину ожидал, что Hibernate переведет это во что-то, использующее предложение «in» в столбце DISCRIMINATOR вместо создания отдельного вызова для каждой реализации.

Я пытался найти это, но, к сожалению, мои результаты загрязняются тем фактом, что мой запрос содержит «спящий режим», «критерии» и «интерфейс», и я постоянно сталкиваюсь со страницами, которые либо объясняют API, либо демонстрируют основные примеры.

Мне известно, что я мог бы создать Критерии для "MyAbstractEntity" вместо "MyInterface" и удалить нежелательные результаты, но я хочу, чтобы эта фильтрация происходила в базе данных.

Нет ли способа сообщить Hibernate, что я хочу всего за один вызов db?

Ответы [ 2 ]

1 голос
/ 22 ноября 2011

Вы можете использовать предложение in для неявного свойства class:

criteria.add(Restrictions.in("myAbstractEntity.class", 
                             new Class[] {MyFirstSubClass.class, MySecondSubClass.class}));

У меня были ошибки с ними в прошлом, когда классы приходилось заменять значениями дискриминатора, но я не помню точно, когда эта ошибка произошла и была ли она исправлена.Таким образом, вы могли бы использовать

criteria.add(Restrictions.in("myAbstractEntity.class", 
                             new String[] {MyFirstSubClass.DISCRIMINATOR_VALUE, MySecondSubClass.DISCRIMINATOR_VALUE}));
0 голосов
/ 22 ноября 2011

Я не мог заставить решение Nizet работать, поэтому мой немного грязный способ сделать это был:

Restrictions.sqlRestriction("{alias}.DISCRIMINATOR in (" + discriminatorValues + ")")

гдеcriminatorValues ​​- статическое поле, инициализированное в статическом блоке с помощью вспомогательного класса Spring.*

    Set<Class <? extends MyAbstractEntity>> result = new HashSet<Class <? extends MyAbstractEntity>>();

    ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
    provider.addIncludeFilter(new AssignableTypeFilter(MyInterface.class));
    Set<BeanDefinition> components = provider.findCandidateComponents("path/to/package/with/subclasses");
    for (BeanDefinition component : components) {
        Class<?> clazz = null;
        try {
            clazz = Class.forName(component.getBeanClassName());
        } catch (ClassNotFoundException e) {
            ; //stuff some WTF-message into the logger
        }

        result.add((Class<? extends MyAbstractEntity>) clazz);
    }

    String sep = "";
    for (Class<? extends MyAbstractEntity> o : result) {
        discriminatorValues += sep + "'" + o.getAnnotation(DiscriminatorValue.class).value() + "'";
        sep = ",";
    }

Не то решение, к которому я хотел обратиться, но полученный SQL выглядит так, как я хотел ... (и новые реализации интерфейса будут включены в запрос без каких-либо дальнейших действий в будущем).дэвы)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...