目录

要用到条件查询,找到了在Hibernate jpa中的实现方法,继承JpaSpecificationExecutor做复杂查询,所以记一笔,如果你有更好的方法,欢迎评论。

JpaSpecificationExecutor提供很多条件查询方法。

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);
}

比如方法:

List<T> findAll(Specification<T> var1);

就可以查找出符合条件的所有数据,如果你的框架使用的是前段分页的技术,那么这个方法就挺简便的。

那么这个方法该如何使用呢?我们看到它需要的参数是一个

org.springframework.data.jpa.domain.Specification对象。那我们就创建这个对象先看看。

Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                return null;
            }
        }

IDE自动生成了要重写的方法toPredicate。

root参数是我们用来对应实体的信息的。criteriaBuilder可以帮助我们制作查询信息。

/**
 * A root type in the from clause.
 * Query roots always reference entities.
 *
 * @param <X> the entity type referenced by the root
 * @since Java Persistence 2.0
 */
public interface Root<X> extends From<X, X> {...}
/**
 * Used to construct criteria queries, compound selections,
 * expressions, predicates, orderings.
 *
 * <p> Note that <code>Predicate</code> is used instead of <code>Expression&#060;Boolean&#062;</code>
 * in this API in order to work around the fact that Java
 * generics are not compatible with varags.
 *
 * @since Java Persistence 2.0
 */
public interface CriteriaBuilder {...}

CriteriaBuilder对象里有很多条件方法,比如制定条件:某条数据的创建日期小于今天。

criteriaBuilder.lessThan(root.get("createDate"), today)

该方法返回的对象类型是Predicate。正是toPredicate需要返回的值。

如果有多个条件,我们就可以创建一个Predicate集合,最后用CriteriaBuilderandor方法进行组合,得到最后的Predicate对象。

/**
     * Create a conjunction of the given restriction predicates.
     * A conjunction of zero predicates is true.
     *
     * @param restrictions zero or more restriction predicates
     *
     * @return and predicate
     */
    Predicate and(Predicate... restrictions);
/**
     * Create a disjunction of the given restriction predicates.
     * A disjunction of zero predicates is false.
     *
     * @param restrictions zero or more restriction predicates
     *
     * @return or predicate
     */
    Predicate or(Predicate... restrictions);

Entity

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.zo.constant.ReportType;
import lombok.Data;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.List;

@Entity
@Table(name = "form")
@Data
public class Form{
    @NotNull
    private Long projectStandardId;
    @Enumerated(EnumType.STRING)
    private ReportType type;
    @ManyToOne
    @JoinColumn(name = "sub")
    private SubItem subItem;
    @NotNull
    private String name;
}

Repository

public interface FormRepository extends JpaRepository<Form,Long>,JpaSpecificationExecutor<Form> {
    List<Form> findAll(Specification<Form> spec);
}

Service

public List<Form> findFormAll(Long standardId, ReportType categoryType,Long subItemId){
    List<Form> formList = null;
    Specification querySpecification = new Specification<Form>() {
        @Override
        public Predicate toPredicate(Root<Form> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            List<Predicate> predicates = new ArrayList<>();
            if (null!=standardId){
                predicates.add(cb.equal(root.get("projectStandardId"),standardId));
            }
            if (null!=categoryType){
                predicates.add(cb.equal(root.get("type"),categoryType));
            }
            if (null!=subItemId){
                predicates.add(cb.equal(root.get("subItem"),subItemId));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        }
    };
    formList = this.formRepository.findAll(querySpecification);
    return formList;
}

and到一起的话所有条件就是且关系,or就是或关系了。

public Page<Article> findAllFuzzy(String keyword,Pageable pageable){
        logger.info("Fuzzy search by keyword: {}",keyword);
        Page<Article> articles = articleRepository.findAll((root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            if (!"".equals(keyword)){
                list.add(cb.like(root.get("title").as(String.class),"%" + keyword + "%"));
                list.add(cb.like(root.get("content").as(String.class),"%" + keyword + "%"));
                list.add(cb.like(root.get("tag").as(String.class),"%" + keyword + "%"));
            }
            Predicate[] predicates = new Predicate[list.size()];
            predicates = list.toArray(predicates);
            query.orderBy(cb.desc(root.get("id").as(Integer.class)));
            return cb.or(predicates);
        },pageable);
        return articles;
    }