Критерии Hibernate для запроса более чем одного класса (или ограничения списка подклассов)

Предположим, у меня есть несколько классов, например:

OpA extends Operation
OpA1 extends OpA
OpA2 extends OpA
OpB extends Operation
OpB1 extends OpB
OpB2 extends OpB
OpB3 extends OpB
OpC extends Operation

                        Operation
                            |
            /-----------------------------\
           /                |              \
         OpA               OpB             OpC
         /                  |
        /                   |
   /------\           /-----------\
  /        \         /      |      \
 OpA1     OpA2     OpB1    OpB2    OpB3

Если я хочу найти некоторые операции, я могу сделать это:

session.createCriteria(Operation.class)
       .add(...)
       .add(...)
       .addOrder(...)
       .setFirstResult(...)
       .setMaxResults(...)
       .list();

Но что, если я хочу применить эти критерии не ко всем операциям типа Operation.class, а только к операциям типов: OpA2 + OpB1 + OpB3 + OpC?

Мой вопрос: как это сделать, используя только критерии Hibernate? Пожалуйста, не используйте HQL.

Примечание. Я не знаю, следует ли мне рассматривать эту проблему как «запрос более чем одного класса» (где все они имеют поля с теми же именами, что и те, которые я запрашиваю), или я должен рассматривать ее как «ограничение запроса по списку подклассов».

Изменить: если бы я мог создать интерфейс TheOnesIWant, а затем заставить классы OpA2, OpB1, OpB3 и OpC реализовать этот интерфейс, это дало бы мне желаемый результат: session.createCriteria(TheOnesIWant.class) Но я не могу этого сделать, потому что Я знаю только те классы, которые хочу запрашивать во время во время выполнения. Приведенная выше иерархия классов является лишь примером.


person MarcG    schedule 07.01.2015    source источник
comment
Можете ли вы написать простой sql, изображающий то, что вы хотите, рассматривая эти классы как таблицу.   -  person VGaur    schedule 07.01.2015
comment
Извините, я не знаю как.   -  person MarcG    schedule 07.01.2015
comment
Не могли бы вы создать интерфейс Criteriable, который реализовывал бы только те классы, к которым вы хотите применять критерии? Тогда session.createCriteria(Criteriable.class)? Никогда не пробовала, но это первое, что приходит на ум :)   -  person ConMan    schedule 07.01.2015
comment
Я не могу, потому что классы, которые мне нужны, постоянно меняются во время выполнения.   -  person MarcG    schedule 07.01.2015
comment
Вы хотите создать этот критерий только в 1 команде? Учитывая, что все классы реализуют операцию, вы можете создать один критерий для каждого класса и объединить все списки для возврата.   -  person Dalton    schedule 09.01.2015
comment
Я не могу создать один критерий для каждого класса, а затем добавить результаты, потому что мне нужно разбиение по страницам. Например, я хочу получить 350 результатов после 15000-го.   -  person MarcG    schedule 09.01.2015


Ответы (1)


В общем, Hibernate имеет очень ограниченную поддержку объединения несвязанных сущностей. Под «несвязанными» я подразумеваю объекты, которые не имеют ссылок друг на друга. Critera API его вообще не поддерживает, а HSQL умеет делать только перекрестное соединение. Не поймите меня неправильно, базовая реализация Criteria/HQL способна объединять несвязанные объекты, но API не предоставляет эту функциональность. (Вы можете выполнять все виды соединений (внутренние, левые, правые, полные) для связанных объектов.) Единственный способ выполнить внутреннее/левое/правое/полное соединение для несвязанных объектов - это собственный sql. Однако, если у несвязанных объектов есть общий родитель, вы можете использовать функцию гибернации, называемую «неявным полиморфизмом»: выбор родителя вернет родителя и все его подклассы. И тогда вы можете ограничить результат списком подклассов.
Попробуйте следующее:

List<Operation> list = session.createCriteria(Operation.class)
    .add(Restrictions.or(
         Property.forName("class").eq(OpA2.class)
        ,Property.forName("class").eq(OpB1.class)
        ,Property.forName("class").eq(OpB3.class)
        ,Property.forName("class").eq(OpC.class)))
    .list();

EDIT:
Вот пример того, как запрашивать свойства, которые не существуют в родительском классе: в этом примере свойства "f" и "value" не существуют в классе Operation, они существуют только в классах OpA2 и OpC.

List<Operation> list = session.createCriteria(Operation.class)
    .add(Restrictions.or(
        Restrictions.and(Property.forName("class").eq(OpA2.class), Restrictions.eq("f", 1))
        , Property.forName("class").eq(OpB1.class)
        , Property.forName("class").eq(OpB3.class)
        , Restrictions.and(Property.forName("class").eq(OpC.class), Restrictions.eq("value", "b"))))
    .list();
person outdev    schedule 10.01.2015
comment
Хорошо, хорошо, все классы, которые у меня есть, действительно связаны общим родителем Operation.class. Но тогда это работает только в том случае, если я запрашиваю какое-то поле, которое фактически существует в самом классе Operation. Если я запрашиваю некоторое поле, которое существует во всех подклассах (OpA2, OpB1, OpB3 и OpC), но НЕ в Operation, я получаю это исключение: MySQLSyntaxErrorException: Not unique table/alias. - person MarcG; 14.01.2015
comment
См. раздел РЕДАКТИРОВАТЬ. - person outdev; 14.01.2015