Filter hibernation criteria using a linked object
I have an object that has a collection of related objects.
public class Student{
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "COURSE_STUDENT_ID" , insertable=false,updatable=false)
private Set <Course> courses;
I want to filter students by course names and student class id. At the moment I was working on how to filter by class ID, but I have no idea how to filter, of course, given that the student has a set of courses and the tables are related. I have read several articles but the code is not the same as the one I already have.
CriteriaBuilder criteriaBuilder = persistenceStore.createCriteriaBuilder();
CriteriaQuery<Object> criteria = criteriaBuilder.createQuery();
Root<Student> root = criteria.from(Student.class);
List<Predicate> params = new ArrayList<Predicate>();
params.add(criteriaBuilder.equal(root.get("classId"),classId));
Predicate[] predicates = new Predicate[params.size()];
params.toArray(predicates);
criteria.select(root);
criteria.where(criteriaBuilder.and(predicates));
Query query = persistenceStore.createQuery(criteria);
List<Student> resultList = query.getResultList();
source to share
First of all, there is a bug in your Entity: the annotation JoinColumn
is being applied to the entity on the back of the relationship, Course
in your case.
So, if an object Course
has a property student
, Student has a property like:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "student")
private Set<Course> courses;
and in the course object you have (it also states that in the db in the course table there is a field called "student":
@JoinColumn(name = "student", referencedColumnName = "id")
@ManyToOne(optional = false)
private Student student;
Read this link for an entry-level explanation on how to map entity relationships.
As for the Criteria Query, since you want to get a list student
S, you can define your CriteriaQuery in a safer way:
CriteriaQuery<Student> criteria = criteriaBuilder.createQuery(Student.class);
As for the question, you should join the tables like this:
SetJoin<Student, Course> courses = root.join("courses");
or, using MetaModel:
SetJoin<Student, Course> courses = root.join(Student_.courses);
(if the OneToMany property was defined as List
or Collection
, you would have to use the corresponding classes ListJoin
and CollectionJoin
).
in courses, you can apply the conditions you want Predicate
(assume the course object has a string property called courseName
):
Predicate p = criteriaBuilder.equal(courses.get("courseName"), "name-to-look-for");
or, using Metamodel:
Predicate p = criteriaBuilder.equal(courses.get(Course_.courseName), "name-to-look-for");
Finally, to correctly align the list of predicates, you can use (at least) two methods:
Predicate p1 = ...;
Predicate p2 = ...;
criteria.where(criteriaBuilder.and(p1, p2));
or
List<Predicate> conditions = new ArrayList<Predicate> ();
conditions.add(p1);
conditions.add(p2);
criteria.where(conditions.toArray(new Predicate[] {}));
See also this excellent article.
source to share