Question

My entity has a collection of another entity on which I need to do a BETWEEN criteria. I do not want to use the native query. I am trying to achieve this using the criteria API.

Below is a short snippet of my entity.

@Entity
@Table(name = "ref_dates")
public class Dates{
    @Id
    @Column(name = "ID")
    private int id;

    @OneToMany(fetch = FetchType.EAGER)
    @JoinTable(
    name="ref_dates_prg",
    joinColumns = @JoinColumn( name="DATE_PRG_ID"),
    inverseJoinColumns = @JoinColumn( name="DATE_ID")
 )    
 private Set<DateInfo> dates;

}

It has several other properties, geter/setters, etc which I have not mentioned here. I need to do a query on this Set for the id's in DateInfo object using between clause. I tried using Expression<Set<DateInfo>> but haven't reached anywhere. Thanks for all the help.

Here is my criteria build up.

final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

final CriteriaQuery<NetPrgTimePeriod> criteriaQuery = criteriaBuilder.createQuery(Dates.class);

List<Predicate> criteriaList = new ArrayList<Predicate>();

final Root<Dates> root = criteriaQuery.from(Dates.class);

Join<Dates, DateInfo> dateJoin = root.join("dates", JoinType.LEFT);

Predicate runDatesRange = criteriaBuilder.between(
        dateJoin.<Integer> get("id"), startDate.getId(), endDate.getId());

criteriaList.add(runDatesRange);

Join<Dates, TimeInfo> timeJoin = root.join("times", JoinType.LEFT);

Predicate timeBlocksRange = criteriaBuilder.between(
        timeJoin.<Integer> get("id"), startTime.getId(), endTime.getId());

criteriaList.add(timeBlocksRange);

criteriaQuery.where(criteriaBuilder.and(criteriaList.toArray(new Predicate[0])));

TypedQuery<NetPrgTimePeriod> query = em.createQuery(criteriaQuery);

List<Dates> results = query.getResultList();
Was it helpful?

Solution

Assuming you actually mapped your collection correctly, the main part you seem to be missing is the Join:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Dates> query = cb.createQuery(Dates.class);

Root<Dates> root = query.from(Dates.class);
Join<Dates, DateInfo> infos = root.join("dates", JoinType.LEFT);

query.distinct(true);
em.createQuery(query.where(cb.between(infos.<Integer>get("id"), 1, 10))).getResultList();

Of course you can substitute metamodel fields where I used strings (which will also obsolete the need for this ugly <Integer> selector - assuming your id is an integer).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top