JPA

Objective

Using JPA to create dynamic queries in a typesafe manner.

The Criteria API includes mechanisms for building queries dynamically at runtime. A Java compiler can check for errors, in contrast to string-based Java Persistence Query Language (JPQL) queries.

Simple Example

The following example returns a list of Groups.


    CriteriaBuilder criteriaBuilder = getCriteriaBuilder();
    CriteriaQuery<Group> query = criteriaBuilder.createQuery(Group.class);
    Root<Group> group = query.from(Group.class);
    
    query.select(group);
    TypedQuery<Group> typedQuery = createTypedQuery(query);
    return typedQuery.getResultList();

Dynamic Where Conditions

The following example dynamically adds Predicates to filter the results at run-time. The example also includes ordering and the application of limits.


    CriteriaBuilder cb = getCriteriaBuilder();
    CriteriaQuery<User> query = cb.createQuery(User.class);
    Root<User> user = query.from(User.class);

    List<Predicate> predicates = new ArrayList();
    if (criteria.getSchoolId() != null){
        Join<User, UserSchoolRelationship> userSchool = user.join("userSchoolRelationships");
        predicates.add(cb.equal(userSchool.get("school"), criteria.getSchoolId()));
    }
    if (criteria.getEnabled() != null)
        predicates.add(cb.equal(user.get("enabled"), criteria.getEnabled()));
    if (criteria.isAllowedOnTablet() != null)
        predicates.add(cb.equal(user.get("allowedOnTablet"), criteria.isAllowedOnTablet()));

    query.select(user)
            .where(predicates.toArray(new Predicate[]{}));

    query.orderBy(cb.asc(user.get("username")));
    return entityManager.createQuery(query)
            .setFirstResult(criteria.getStart())
            .setMaxResults(criteria.getLimit())
            .getResultList();

Casting to Custom Types

The following example shows how to return a custom object from a query. Here we have created a new object to return to the service layer, CustomModelForCast. This can be especially useful for any aggregate functions used in queries. In the example, we are returning a simple object that contains the company and the count of users in that company.


    public class CustomModelForQueryResults{
       private Company company;
       private Long count;

       public CustomModelForQueryResults(Company company, Long count){
           this.company = company;
           this.count = count;
       }

       public Company getCompany() {
           return company;
       }

       public void setStore(Company company) {
           this.company = company;
       }

       public Long getCount() {
           return count;
       }

       public void setCount(Long count) {
           this.count = count;
       }
    }


    public List<CustomModelForQueryResults> countRequestsGroupedByStore(List<Status> statuses) {

       CriteriaBuilder builder = entityManager.getCriteriaBuilder();
       CriteriaQuery<CustomModelForQueryResults> query = builder.createQuery(CustomModelForQueryResults.class);
       Root<User> sr = query.from(User.class);
       Join<User, Company> company= sr.join("company");

       query.multiselect(company, builder.count(user)).where(sr.get("status").in(statuses)).groupBy(sr.get("company"));

       TypedQuery<CustomModelForQueryResults> q = entityManager.createQuery(query);
       return q.getResultList();
    }

Conclusion

Because of the above examples, you can see how some of the benefits of JPA 2 Criteriabuilder work. As well as avoiding the issues associated with JPQL, we can build flexible queries and avail of the CriteriaQuery’s query functions.

Greenfinch Technology has several expert custom Java developers. If you would like to talk to us about having custom software developed using Java you can contact us for a no-obligation discussion at 01 818 2949 or please use our contact form.

Greenfinch Technology

Greenfinch Technology