AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

Criteria queries with Spring Data

Although Spring Data provides easy ways to obtain database results, there are times when a programmatic approach is required. In this article, we will see how to construct Criteria Queries with Spring Data using Spring Boot.

For complex queries with conditions on multiple fields, using Criteria is the most suitable approach.

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

With this Spring Boot starter, we will add all the necessary JPA dependencies.

Why use Criteria Queries with Spring Data

Criteria Queries provide a flexible and programmatic approach for constructing complex queries in Spring Data. They allow you to define query conditions dynamically, handle multiple criteria, and build queries based on runtime conditions. This gives you more control and flexibility compared to static queries defined in annotations or methods. Additionally, Criteria Queries seamlessly integrate with other Spring Data features and repositories, allowing you to leverage existing functionality while still benefiting from the power of dynamic queries.

Creating Criteria Queries by Extending Repository

In many cases, we need to create queries where the automatic queries provided by Spring Data are not sufficient, such as adding multiple conditions. For such cases, we can use the Criteria API.

To continue using JpaRepository and have access to default methods, we will create an interface that extends JpaRepository and the interface where we define custom methods.

EntityManager will be necessary to use the Criteria API.

interface ResourceRepository<T> {
    List<T> findByNameAndSurname(String name, String title);
}

interface UserRepository extends JpaRepository<User, Long>, ResourceRepository<User> {
}

@Repository
class UserRepositoryImpl implements UserRepository {
 
  @PersistenceContext
  EntityManager em;

@Override
public List<User> findUsersByNameAndSurname(String name, String surname) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<User> cq = cb.createQuery(User.class);
 
    Root<User> user = cq.from(User.class);
    List<Predicate> predicates = new ArrayList<>();
     
    if (name != null) {
        predicates.add(cb.equal(user.get("name"), name));
    }
    if (surname != null) {
        predicates.add(cb.equal(user.get("surname"),surname));
    }
    cq.where(predicates.toArray(new Predicate[0]));
 
    return em.createQuery(cq).getResultList();
}

When declaring ResourceRepository as a dependency, Spring will search for the implementation and use it to call the methods we have defined within the interface. This way, we will have our new method along with the methods provided by JPA.

Queries with JPA specification

Spring Data contains the interface org.springframework.data.jpa.domain.Specification, which provides several methods for encapsulating a predicate.

The best way to understand how specifications work is through an example:

Let’s create a class that returns a Specification:

public class specificationExample {

  public static Specification<UserDbo> getName(String name) {
     return (Specification<UserDbo>) (user, query, cb) -> {
       cb.equal(user.get("name"), name);
   }
  }
}

With the previous example, it would be equivalent to performing an SQL query where the WHERE clause is user.name = ‘name’. However, the power of using specifications lies in the ability to add conditions as shown in the following example:

public class specificationExample {

  public static Specification<UserDbo> getName(String name, String surname) {
     return (Specification<UserDbo>) (user, query, cb) -> {
       List<Predicate> predicates = new ArrayList<>();            
       predicates.add(cb.equal(user.get("name"), name);
       
       if (null != surname) {
            predicates.add(cb.equal(user.get("surname"), surname);
       }
    return cb.and(predicates.toArray(Predicate[]::new));

    }
  }  
}

In the previous example, we added two predicates to a list with conditions, including a programmatic check for non-null last name.

To use these methods, we can create a bean of the specificationExample class and call the method, or extend the org.springframework.data.jpa.repository.JpaSpecificationExecutor<T> repository. Don’t forget to also extend JpaRepository to make use of the default methods provided by Spring Data.

Conclusion

In this article about Criteria Queries with Spring Data, we have seen how to use the Criteria API by extending Repository. Furthemore we have seen how add new methods that are executed with Predicate, as well as using Specification.

If you want to practice, you can perform some tests with H2

If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!

Leave a Reply

Your email address will not be published. Required fields are marked *