Spring Data Jpa Learning-Dynamic Query

Keywords: Spring Java Attribute SQL

Specifications dynamic query

Sometimes when we query an entity, the given condition is not fixed, so we need to dynamically construct the corresponding query statement. In Spring Data JPA, we can query through Jpa Specification Executor interface. Compared with JPQL, its advantage is type-safe and more object-oriented.

Jpa Specification Executor Interface

Method defined in the JpaSpecification Executor interface:

import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;

public interface JpaSpecificationExecutor<T> {
	//Query an object on condition
    Optional<T> findOne(@Nullable Specification<T> var1);
	//Query Object Sets Based on Conditions
    List<T> findAll(@Nullable Specification<T> var1);
	//Query and paginate according to conditions
     	//pageable: Paging parameters
     	//Return value: Paging pageBean, provided by spring data JPA
    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
    //Sort Query Query
         // Sort: Sort parameter
    List<T> findAll(@Nullable Specification<T> var1, Sort var2);
	//Statistical query
    long count(@Nullable Specification<T> var1);
}

//Remarks
//	If the NULL value can be passed in, it is marked as @Nullable, and if not, it is marked as @Nonnull.

For Jpa Specification Executor, we can find that this interface method is basically defined around the Specification interface. We can simply understand that a Specification constructs a query condition.
——> We need to customize our own Specification implementation class.

Specfication interface

In the Specification interface, only one method is defined as follows:

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
//Root: The root object of the query (any attribute of the query can be retrieved from the root object)
//CriteriaQuery: Top-level query object, custom query mode (Understanding: Normally not used)
//Criteria Builder: A query constructor used to construct query conditions that encapsulate many query condition methods
public interface Specification<T> {
    Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}

Methodological correspondence

Method SQL Correspondence Syntax
equle filed = value
gt(greaterThan ) filed > value
lt(lessThan) filed < value
ge(greaterThanOrEqualTo ) filed >= value
le( lessThanOrEqualTo) filed <= value
notEqule filed != value
like filed like value
notLike filed not like value
and Conditions 1 and 2 and 3... And condition n
or Conditions 1 or 2 or 3... Or condition n

Example

   / ** Customize dynamic queries
     * (1) Instance Specification Interface
     *—— Rewriting the toPredicate method
     ** root: Gets the object properties that need to be queried
     ** Criteria Builder: Constructs query conditions and encapsulates many query conditions internally (fuzzy query, precise matching)
     * (2) Invoking JpaSpecification Executor Interface Method Query
     * (3) Use of query results
     */

Example 1, equal exact query

    @Test
    public void testSpec01(){
        //(1) Implementing Specification Interface
        Specification<Student> spec = new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //1. Get the attributes of the comparison
                Path<Object> name = root.get("stuName");
                //2. Constructing Query Conditions
                Predicate predicate = criteriaBuilder.equal(name, "Xie");

                return predicate;
            }
        };

        //(2) Invoking JpaSpecification Executor Interface Method Query
        Optional<Student> optional = repository.findOne(spec);

        // (3) Use of query results
        if (optional.isPresent()){
            System.out.println("Query out the results:"+optional.get());
        }else {
            System.out.println("No query results!!!");
        }
    }

Example 2, like fuzzy query

    /**
     * like Fuzzy query
     */
    @Test
    public void testSpec2(){
        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                Path<Object> name = root.get("stuName");
                Predicate predicate = criteriaBuilder.like(name.as(String.class), "%Zhao%");
                return predicate;
            }
        };
        List<Student> students = repository.findAll(spec);
        students.forEach(a->System.out.println(a.toString()));

    }

Example 3, Combining and Queries

    /**
     * Composite query
     */
    @Test
    public void testSpec3(){
        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"Xie");

                Predicate predicate = criteriaBuilder.and(predicate01, predicate02);
                return predicate;
            }
        };

        List<Student> students = repository.findAll(spec);
        students.forEach(a->System.out.println(a.toString()));
    }

Example 4, combined or queries

    /**
     * Combined or query
     */
    @Test
    public void testSpec4(){
        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"Xie");

                Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
                return predicate;
            }
        };
        List<Student> students = repository.findAll(spec);
        students.forEach(a->System.out.println(a.toString()));
    }

Example 5, Query Sorting

    /**
     * Query ranking
     */
    @Test
    public void testSpec5(){
        Sort sort =new Sort(Sort.Direction.ASC,"age");

        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"Xie");

                Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
                return predicate;
            }
        };
        List<Student> students = repository.findAll(spec,sort);
        students.forEach(a->System.out.println(a.toString()));
    }

Example 6, Query Paging

    /**
     * Query paging
     */

    @Test
    public void testSpec6(){
        Sort sort =new Sort(Sort.Direction.ASC,"age");
        PageRequest pageRequest = PageRequest.of(1,2,sort);

        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"Xie");

                Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
                return predicate;
            }
        };
        Page<Student> studentPage = repository.findAll(spec, pageRequest);
        long totalElements = studentPage.getTotalElements();//Get the total number
        System.out.println("Quantity of data for query:"+totalElements);
        int totalPages = studentPage.getTotalPages();//Get the total number of pages
        System.out.println("Number of data pages for query:"+totalElements);
        List<Student> students = studentPage.getContent();//Get all the content
        students.forEach(a->System.out.println(a.toString()));
    }

Posted by discosuperfly on Wed, 02 Oct 2019 11:22:27 -0700