2

I have a entity University having a list of abstract Person. There are two implementations Student and Professor. Now I would like to find all Universities without any Student by a JPA Query.

University-Class

@Entity
public class University {
    @OneToMany(targetEntity = Person.class,
            cascade = CascadeType.ALL,
            fetch = FetchType.EAGER,
            mappedBy = "university",
            orphanRemoval = true)
    private List<Person> persons = new ArrayList<>();
}

Abstract Person class

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type")
public abstract class Person {

    @OneToOne(fetch = FetchType.LAZY)
    private University university;

}

Student Implementation

@Entity
@DiscriminatorValue("STUDENT")
public class Student extends Person {

    @NotNull
    private String matriculation;
}

A native SQL query would be as following. But I have no idea how to translate that to a JPA Named Query or - also ok - in Criteria API.

select *
from university
    where id not in (
        select distinct u.id
        from university u
            join person p on u.id = p.university_id
            where p.type = 'STUDENT'
    )
;
Rokko_11
  • 837
  • 2
  • 10
  • 24
  • Does this answer your question? [Getting error saying class not mapped with named query](https://stackoverflow.com/questions/55846658/getting-error-saying-class-not-mapped-with-named-query) – A.Casanova Mar 10 '23 at 10:42

2 Answers2

0

the implementation with criteria look like this:

// Define the objects from criteria
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<University> cq = cb.createQuery(University.class);

// From clause
Root<University> rootUniversity = cq.from(University.class);

//Create subquery assuming that the university has an ID (which is mandatory) and is of type Long
Subquery<Long> sq = cq.subquery(Long.class);
Root<University> sqRootUniversity = sq.from(University.class);
Join<University,Person> sqJoinPerson =  sqRootUniversity.join(University_.persons,JoinType.INNER);
sq.where(cb.equal(sqJoinPerson.get(Person_.type),"STUDENT"));
sq.select(sqRootUniversity.get(University_.id)).distinct(true);

//Add subquery to where
cq.where(rootUniversity.get(University_.id).in(sq.getSelection()).not());

// Select clause
cq.select(rootUniversity);

//Get results
List<University> universities = entityManager.createQuery(cq).getResultList();
JLazar0
  • 1,257
  • 1
  • 11
  • 22
0

Take a look at this other answer.

You just need to use @NamedQuery or @NamedNativeQuery:

@NamedQueries({
    @NamedQuery( name="<your-query-name>" , query="SELECT p FROM Person p")
 })

@Entity(name="Person")
@Table(name="person")
public abstract class Person {
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
A.Casanova
  • 555
  • 4
  • 16