Spring Data JPA greatly simplifies persistence layer development, but in practice there are many areas where advanced dynamic queries are required
Criteria API
Criteria queries are based on the concept of a metamodel defined for the managed entities of a concrete persistence unit, which can be an entity class, an embedded class, or the parent of a map.
CriteriaQuery Interface: Represents a specific top-level query object that contains the various parts of the query, such as SELECT, FROM, WHERE, Group by, Order BY, etc. Note: CriteriaQuery objects work only for Criteria queries of entity types or embedded types
Root interface: Represents the Root object of the Criteria query, which defines the entity type for future navigation to obtain the desired results, similar to the FROM clause in SQL queries
1: The Root instance is typed and defines the types that can appear in the FROM clause of the query.
2: The query root instance can be obtained by passing an entity type to the AbstractQuery.from method.
3: Criteria queries, which can have multiple query roots.
4: AbstractQuery is the parent class of the CriteriaQuery interface, which provides methods for obtaining the query root. CriteriaBuilder interface: the builder object used to build a CritiaQuery. Predicate: A simple or complex Predicate type that acts as a condition or combination of conditions
If the compiler can perform syntactic correctness checks on the query, then the query is type-safe for Java objects. Version 2.0 of the Java™Persistence API (JPA) introduces the Criteria API, which first introduces type-safe queries into Java applications and provides a mechanism for dynamically constructing queries at run time.
The JPA metamodel
In JPA, standard queries are based on the concept of a metamodel. A metamodel is defined for the managed entities of a concrete persistence unit. These entities can be entity classes, embedded classes, or the parent classes of the map. The classes that provide meta-information about managed entities are metamodel classes.
The biggest advantage of using metamodel classes is that instantiation allows access to persistent attributes of entities at compile time. This feature makes criteria queries more type-safe.
Item_ is the metamodel corresponding to the Item entity class
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Item.class)
public abstract class Item_ {
public static volatile SingularAttribute<Item, Integer> itemId;
public static volatile SingularAttribute<Item, String> itemName;
public static volatile SingularAttribute<Item, Integer> itemStock;
public static volatile SingularAttribute<Item, Integer> itemPrice;
}Copy the code
Instead of creating such a metamodel manually, add a plug-in to Maven, and the @Entity annotated class will automatically generate the corresponding metamodel after compilation
<! Hibernate JPA automatic metamodel generation
<! -- Related dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.2.10. The Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0. The Final</version>
</dependency>Copy the code
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
</plugin>Copy the code
There is more than one method, see Chapter 2. Usage
Query simple Demo using Criteria
@Service
public class ItemServiceImpl implements ItemService {
@Resource
private EntityManager entityManager;
@Override
public List<Item> findByConditions(String name, Integer price, Integer stock) {
Create the CriteriaBuilder security query factory
// A CriteriaBuilder is a factory object, the beginning of a security query. Used to build JPA security queries.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// Create a CriteriaQuery security query subject clause
CriteriaQuery objects must work on Criteria queries on entity types or embedded types.
CriteriaQuery<Item> query = criteriaBuilder.createQuery(Item.class);
//Root defines the types that can appear in the From clause of the query
Root<Item> itemRoot = query.from(Item.class);
//Predicate filters conditions that can build a WHERE sentence
// Select * from List
List<Predicate> predicatesList = new ArrayList<>();
//name fuzzy query,like statement
if(name ! =null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
itemRoot.get(Item_.itemName), "%" + name + "%")));
}
ItemPrice <= statement
if(price ! =null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
itemRoot.get(Item_.itemPrice), price)));
}
//itemStock greater than or equal to >= statement
if(stock ! =null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.ge(
itemRoot.get(Item_.itemStock), stock)));
}
//where() concatenates query conditions
query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
TypedQuery<Item> typedQuery = entityManager.createQuery(query);
List<Item> resultList = typedQuery.getResultList();
returnresultList; }}Copy the code
The statements corresponding to each method in the criteriaBuilder
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
It would feel like too much trouble to write this for every dynamic query.
In fact, when using Spring Data JPA, as long as our Repo layer interface inherits the JpaSpecificationExecutor interface we can use Specification for dynamic queries, Let’s take a look at the JpaSpecificationExecutor interface:
public interface JpaSpecificationExecutor<T> {
T findOne(Specification<T> var1);
List<T> findAll(Specification<T> var1);
Page<T> findAll(Specification<T> var1, Pageable var2);
List<T> findAll(Specification<T> var1, Sort var2);
long count(Specification<T> var1);
}Copy the code
There is an important interface Specification here
public interface Specification<T> {
Predicate toPredicate(Root
var1, CriteriaQuery
var2, CriteriaBuilder var3)
;
}Copy the code
This interface has only one method, which returns the data structure of the dynamic query and is used to construct the SQL for various dynamic queries
Specification Interface Example
public Page<Item> findByConditions(String name, Integer price, Integer stock, Pageable page) {
Page<Item> page = itemRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicatesList = new ArrayList<>();
//name fuzzy query,like statement
if(name ! =null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.like(
root.get(Item_.itemName), "%" + name + "%")));
}
ItemPrice <= statement
if(price ! =null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
root.get(Item_.itemPrice), price)));
}
//itemStock greater than or equal to >= statement
if(stock ! =null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.ge(
root.get(Item_.itemStock), stock)));
}
return criteriaBuilder.and(
predicatesList.toArray(new Predicate[predicatesList.size()]));
}, page);
return page;
}Copy the code
This is because the Specification
parameter in the findAll(Specification
var1, Pageable var2) method is an anonymous inner class
So here we can use lambda expressions to simplify the code directly.
Writing this way, it is much simpler than securely querying factories using CriteriaBuilder.
Call:
Page<Item> itemPageList = findByConditions("Car".300.null.new PageRequest(1.10));Copy the code
The Specification
interface and metamodel of JPA are used to implement dynamic query.
FindByConditions = findByConditions = findByConditions = findByConditions = findByConditions = findByConditions = findByConditions = findByConditions = findByConditions The simpler the better, of course.
The next article will cover a more convenient use of JPASpecification. The original link: Spring – Data – JPA criteria queries | fire yao