JPA 2.0 CriteriaQuery with predicate on type being a class or any subclass of

868 views Asked by At

Assuming the following entity classes and hierarchy:

@Entity
Class Ticket {

    @ManyToOne(optional = true)
    private Customer customer;    

}

@Entity
Class Customer {}

@Entity
Class Person extends Customer {}

@Class CustomPerson extends Person {}

How can I query for all tickets which have customer of type Person or any subclass of Person (i.e. CustomPerson)?

I can easily create a predicate on type:

Predicate p = criteriaBuilder.equal(Ticket_...type(), criteriaBuilder.literal(Person.class));

but this will filter out CustomPerson.

Unless there is a generic way to handle this (in JPA 2.0), I could overcome the issue if I could determine at runtime all entities extending Person; in this scenario I could use

Predicate p = criteriaBuilder.in(Ticket_...type(), listOfPersonSubclasses);
2

There are 2 answers

1
Chris On BEST ANSWER

JPA 2.0 doesn't offer a generic way, so you would have to list all the subclasses, or change the query so that it is based off your Person class instead. For example "Select t from Person p, ticket t where t.customer=p"

JPA 2.1 introduced 'treat' which allows you to downcast and operate on the entity as if it were a certain class. Since any subclass is also an instance, it filters exactly as you seem to require. https://wiki.eclipse.org/EclipseLink/Release/2.5/JPA21#Treat

You can use it as a join or in the where clause, but an example might be:

"Select t from Ticket t join treat(t.customer as Person) p"
0
Dragan Bozanovic On

If there is no easy way in newer versions of JPA, you could get the mapping metadata from the underlying Session and find all the mapped subclasses programmatically (you may do it lazily and cache the results).

To get the session:

org.eclipse.persistence.sessions.Session session = 
     ((org.eclipse.persistence.internal.jpa.EntityManagerImpl) 
                 em.getDelegate()).getSession();