12

I am building a query on a generic table "Sample" and I have several types which inherit from this table "SampleOne", "SampleTwo". I require a query like :

select s from Sample where s.type = :type

where type would be a discriminator value of the table. Is it possible in any way ( and avoid to create an entity specific queries, one for each SampleOne, SampleTwo... etc )

I would greatly appreciate any input in this topic,

Kind regards, P.

redbull
  • 735
  • 3
  • 12
  • 21

4 Answers4

16

In JPA 2.0 you can use TYPE expression (though currently it doesn't work with parameters in Hibernate, see HHH-5282):

select s from Sample s where TYPE(s) = :type

The similar Hibernate-specific expression is .class:

select s from Sample s where s.class = :type
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • Sorry to start new discussion on similar topic but does it work if I provide an abstract class as :type? – Suken Shah Sep 05 '14 at 02:16
  • According to https://hibernate.atlassian.net/browse/HHH-4881 this has been fixed in Hibernate 4.0.0.CR5 – Wim Deblauwe Feb 05 '15 at 07:54
  • Some missing information: "TYPE" is a "JPQL Special Operator" taking in argument element name (s), and maybe compared to the simple class name, Here is a more explicit example (working now in hibernate, no need for a workaround) `SELECT prj FROM Project prj WHERE TYPE(prj) = LargeProject` or using IN `SELECT prj FROM Project prj WHERE TYPE(prj) IN ( MediumProject, LargeProject)` – pdem Sep 17 '19 at 09:21
4

Here's the relevant section of the Java EE 6 tutorial:

Abstract Entities

An abstract class may be declared an entity by decorating the class with @Entity. Abstract entities are like concrete entities but cannot be instantiated.

Abstract entities can be queried just like concrete entities. If an abstract entity is the target of a query, the query operates on all the concrete subclasses of the abstract entity:

@Entity
public abstract class Employee {
    @Id
    protected Integer employeeId;
    ...
}
@Entity
public class FullTimeEmployee extends Employee {
    protected Integer salary;
    ...
}
@Entity
public class PartTimeEmployee extends Employee {
    protected Float hourlyWage;
}

If I read this right, your query:

select s from Sample where s.type = :type

Should only return elements of the specified subtype if type is the discriminator column, so the only thing that's left for you to do is to cast the result list to your requested sub type.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
2

You still have to be carefull in Hibernate 4.3.7, because there is still an issue with the implementation of TYPE(), for example:

from SpoForeignPilot sfp where TYPE(sfp.partDocument) = :type

This query doesn't work as it incorrectly checks the type of SpoForeignPilot and not the type of the document.

You can workaround this issue by doing something like this:

select sfp from SpoForeignPilot sfp join sfp.partDocument doc where TYPE(doc) = :type
Kalle Richter
  • 8,008
  • 26
  • 77
  • 177
  • This adds nothing new to a five-year-old question. – meskobalazs Aug 01 '16 at 11:37
  • 3
    I just wanted to warn people who want to use the proposed solution (use TYPE in jpa 2) to more complex queries, there is still an issue (I encountered this problem when using the solution in this thread). You are right, that the query in the question doesn't expose this issue. – Wim De Rammelaere Aug 17 '16 at 19:31
  • @WimDeRammelaere after hours of scratching my head, your answer helped me to find the problem with my query. Bottom line is, when I used **type** in a where clause it worked when applied to joins, but could not find any results when used on a path expression. – Maciek Oct 29 '17 at 23:29
0

Do this in your repository

@Query("SELECT p FROM BaseUserEntity p where p.class=:discriminatorValue")
    public List<BaseUserEntity> findByDiscriminatorValue(@Param("discriminatorValue") String discriminatorValue);

Where BaseUserEntity is your parent entity

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103