Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Criteria to query more than one class (or restrict by a list of subclasses)

Suppose I have some classes, like this:

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

If I want to find some operations, I can do this:

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

But what if I want to apply these criteria not to all operations of type Operation.class, but only to those of types: OpA2 + OpB1 + OpB3 + OpC?

My Question: How can I do it using Hibernate Criteria only? No HQL, please.

Note: I don't know if I should view this problem as "querying more than one class" (where all of them have fields with the same names as the ones I am querying), or if I view it as "restricting a query by a list of subclasses".

Edit: If I could create an interface TheOnesIWant, and then make classes OpA2, OpB1, OpB3 and OpC implement this interface, this would yield the result I want: session.createCriteria(TheOnesIWant.class) But I can't do this, because I only know the classes I want to query at runtime. The above class hierarchy is just an example.

like image 867
MarcG Avatar asked Jan 07 '15 02:01

MarcG


People also ask

What is Criteria query in hibernate?

Criteria in Hibernate can be used for join queries by joining multiple tables, useful methods for Hibernate criteria join are createAlias(), setFetchMode() and setProjection() Criteria in Hibernate API can be used for fetching results with conditions, useful methods are add() where we can add Restrictions.

What is restriction in hibernate criteria?

1.2. The Restriction class in hibernate provide several methods that can be used as conditions (also known as Criterion). These conditions are added to a criteria object with the add() method. This method takes an org. hibernate.


1 Answers

In general, Hibernate has very limited support for joining unrelated entities. By "unrelated" I mean entities that don't have references to each other. Critera API doesn't support it at all, and HSQL can do only cross join. Don't get me wrong, the underlying Criteria/HQL implementation is capable of joining unrelated entities, but the API do not expose this functionality. (You can do all kinds of joins (inner, left, right, full) on related entities.) The only way to do inner/left/right/full join on unrelated entities, is native sql. However, if the unrelated entities have common parent, you can use a hibernate feature called "implicit polymorphism": selecting the parent, will return parent and all its sub-classes. And then you can restrict the result to list of sub-classes.
So try this:

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:
Here is a example how to query properties that do not exist in the parent class: In this example properties "f" and "value" don't exist in the Operation class, they only exist in OpA2 abd OpC classes.

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();
like image 192
outdev Avatar answered Nov 15 '22 03:11

outdev