Although Spring Data JPA greatly simplifies the development of the persistence layer, in actual development, advanced dynamic queries are required in many places.
Criteria API
Criteria queries are based on the concept of a metamodel defined for the managed entities of a specific persistence unit, which can be entity classes, embedded classes, or mapped parent classes.
CriteriaQuery interface: Represents a specific top-level query object, which contains various parts of the query, such as: select, from, where, group by, order by, etc. Note: CriteriaQuery object only works on Criteria queries of entity type or embedded type.
Root interface: The root object representing the Criteria query. The query root of the Criteria query defines the entity type. It can get the desired result for future navigation. It is similar to the FROM clause in the SQL query.
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 query, you can have multiple query roots.
4: AbstractQuery is the parent class of the CriteriaQuery interface, which provides methods for getting the root of the query. CriteriaBuilder interface: The constructor object Predicate used to build CritiaQuery: a simple or complex predicate type, which is equivalent to a conditional or conditional combination
If the compiler is able to perform a syntax correctness check on the query, the query is type-safe for Java objects. The 2.0 version of the JavaTM Persistence API (JPA) introduces the Criteria API, which for the first time introduces type-safe queries into Java applications and provides a mechanism for dynamically constructing queries at runtime.
JPA metamodel
In JPA, standard queries are based on the concept of a metamodel. Metamodels are defined for managed entities of a specific persistence unit. These entities can be entity classes, embedded classes, or mapped parent classes. Providing managed entities The class of meta information is the metamodel class.
The biggest advantage of using a metamodel class is that it can access the entity's persistent properties at compile time by instantiating it. This feature makes the criteria query more type-safe.
as follows,ItemMetamodel corresponding to the entity classItem_
@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 code
Such a meta model does not need to be created manually. Add a plugin to Maven. After compiling, the @Entity annotated class will automatically generate the corresponding metamodel.
<!--hibernate JPA auto-generate metamodel -->
<!-- Related dependencies -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.2.10.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>Copy 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 code
There is more than one method, see:Chapter 2. Usage
Use criteria to query simple demos
@Service
public class ItemServiceImpl implements ItemService {
@Resource
private EntityManager entityManager;
@Override
public List<Item> findByConditions(String name, Integer price, Integer stock) {
/ / Create CriteriaBuilder security query factory
//CriteriaBuilder is a factory object, the beginning of a secure query. Used to build JPA security queries.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
/ / Create a CriteriaQuery security query main statement
//CriteriaQuery objects must work on Criteria queries on entity types or embedded types.
CriteriaQuery<Item> query = criteriaBuilder.createQuery(Item.class);
//Root defines the type that can appear in the From clause of the query
Root<Item> itemRoot = query.from(Item.class);
//Predicate filter conditions. Possible conditions for constructing where clauses
/ / Here use List to store a variety of query conditions, to achieve dynamic query
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 is less than or equal to <= statement
if (price != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
itemRoot.get(Item_.itemPrice), price)));
}
//itemStock is greater than or equal to >= statement
if (stock != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.ge(
itemRoot.get(Item_.itemStock), stock)));
}
//where() splicing query conditions
query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
TypedQuery<Item> typedQuery = entityManager.createQuery(query);
List<Item> resultList = typedQuery.getResultList();
return resultList;
}
}Copy code
The corresponding statement in each method of 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
If every dynamic query is written like this, it would be too much trouble.
In fact, when using Spring Data JPA, as long as our Repo layer interface inherits the JpaSpecificationExecutor interface, we can use the Specification for dynamic query. 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 code
There is a very important interface here.Specification
public interface Specification<T> {
Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}Copy code
This interface has only one method, which returns the data structure of the dynamic query and is used to construct 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 is less than or equal to <= statement
if (price != null) {
predicatesList.add(
criteriaBuilder.and(
criteriaBuilder.le(
root.get(Item_.itemPrice), price)));
}
//itemStock is 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 code
Here because
findAll(Specification<T> var1, Pageable var2)Method parameterSpecification<T>Is an anonymous inner classThen you can directly simplify the code directly with lambda expressions.
Writing this way is much simpler than using the CriteriaBuilder to safely query the factory.
transfer:
Page<Item> itemPageList = findByConditions("car", 300, null, new PageRequest(1, 10));Copy code
Using JPASpecification<T>The interface and metamodel implement dynamic query.
In fact, every place that needs dynamic query needs to write a similarfindByConditionsMethod, it feels very troublesome. Of course, the more simplified the better.
The next one will talk about a JPASpecificationMore convenient to use.
Original link:Spring-Data-JPA criteria Search |