0

Say I have an entity

@Entity
public class Test {
   @ManyToMany
   @JoinTable(..etc..)
   private List<Subject> subjects; // School subjects this test is associated with
   ....

And an entity

@Entity
public class Exam extends Test {
   // Inherits subjects from test
   // Does some things specific to exams
   ...

And I want to write a criteria query (with metamodels) that gives me only the Exams associated with a certain Subject. My question is: how do I write this query?

What I've tried is the following:

If I write

    CriteriaBuilder cb = em.getCriteriaBuilder();  // em is the EntityManager
    CriteriaQuery<Exam> cq = cb.createQuery(Exam.class);
    Root<Exam> root = cq.from(Exam.class);

    cq.where(cb.isMember(subject, root.get(Exam_.subjects)));

    return em.createQuery(cq);

the compiler won't compile it, saying error: no suitable method found for get(ListAttribute<Test,Subject>). Intuitively it feels as if this should be the solution, but inheritance won't go far enough. It won't work either if I omit the metamodel reference in the query and replace it with root.get("subjects").

If I write

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Exam> cq = cb.createQuery(Exam.class);
Root<Test> root = cq.from(Test.class);

cq.where(cb.isMember(subject, root.get(Exam_.subjects)));

return em.createQuery(cq);

This feels wrong, but it does compile. However, upon actually executing the code I am presented with an exception: IllegalStateException: No explicit selection and an implicit one could not be determined which I interpret as a consequence of juggling around the types for the Root. Trying root.get(Test_.subjects) yields the same result.

I use Hibernate as my JPA implementation, but I try to stick to JPA Criteria Queries.

DCKing
  • 4,253
  • 2
  • 28
  • 43

1 Answers1

0

In JPQL (which I really advise you to use when you don't need a dynamically generated query), you would write it like this:

select e from Exam e
inner join e.students student
where student.id = :studentId

If you really want to use the Criteria API to write this query, do the same thing: create a join and check that the ID of the joined entity is equal to the given student ID. It should look like this:

Join<Exam, Student> studentJoin = root.join(Exam_.students);
cq.where(qb.equal(studentJoin.get(Student_.id), student.getId());
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks for your input - your code yields 0 results from the database for queries that should deliver a handful, so I'll try experimenting a little more with joins before I mark it correct. – DCKing Feb 20 '13 at 23:21