1. 程式人生 > >Spring Data JPA複雜查詢

Spring Data JPA複雜查詢

在使用Spring Data JPA框架時,可以按照符合框架規則的自定義方法或@Query進行固定條件查詢。如果是動態條件查詢框架也提供了介面。

public interface JpaSpecificationExecutor<T>

1.符合框架規則的自定義方法:

 Supported keywords inside method names
Keyword Sample JPQL snippet

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = 1?

Between

findByStartDateBetween

… where x.startDate between 1? and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age ⇐ ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> age)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

2.@Query查詢:

  @Modifying
  @Transactional
  @Query("DELETE FROM UnitRevocationRecord WHERE rid in (:ids)")
  void deleteUnitRevocationRecordByIds(@Param("ids") List<String> ids);

3.JpaSpecificationExecutor複雜查詢
這個介面的使用和其它介面一樣,在你的Dao介面繼承即可。

public interface UnitRevocationDao extends PagingAndSortingRepository <UnitRevocationRecord, String>, JpaSpecificationExecutor<UnitRevocationRecord> {}

JpaSpecificationExecutor介面提供了很多的條件查詢的介面:

/**
 * Interface to allow execution of {@link Specification}s based on the JPA criteria API.
 * 
 * @author Oliver Gierke
 */
public interface JpaSpecificationExecutor<T> {

	/**
	 * Returns a single entity matching the given {@link Specification}.
	 * 
	 * @param spec
	 * @return
	 */
	T findOne(Specification<T> spec);

	/**
	 * Returns all entities matching the given {@link Specification}.
	 * 
	 * @param spec
	 * @return
	 */
	List<T> findAll(Specification<T> spec);

	/**
	 * Returns a {@link Page} of entities matching the given {@link Specification}.
	 * 
	 * @param spec
	 * @param pageable
	 * @return
	 */
	Page<T> findAll(Specification<T> spec, Pageable pageable);

	/**
	 * Returns all entities matching the given {@link Specification} and {@link Sort}.
	 * 
	 * @param spec
	 * @param sort
	 * @return
	 */
	List<T> findAll(Specification<T> spec, Sort sort);

	/**
	 * Returns the number of instances that the given {@link Specification} will return.
	 * 
	 * @param spec the {@link Specification} to count instances for
	 * @return the number of instances
	 */
	long count(Specification<T> spec);
}

在這些方法中,可以看到查詢需要Specification型別的引數

/**
 * Specification in the sense of Domain Driven Design.
 * 
 * @author Oliver Gierke
 * @author Thomas Darimont
 * @author Krzysztof Rzymkowski
 */
public interface Specification<T> {

	/**
	 * Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
	 * {@link Root} and {@link CriteriaQuery}.
	 * 
	 * @param root
	 * @param query
	 * @return a {@link Predicate}, may be {@literal null}.
	 */
	Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

root引數用來對應實體的資訊的。criteriaBuilder可以幫助我們製作查詢資訊,它提供了很多的方法:大於,小於,等於等。如果有多個條件,我們就可以建立一個Predicate集合,最後用CriteriaBuilder的and和or方法進行組合,得到最後的Predicate物件。

示例程式碼:

public PageQueryData<UnitRevocationListDto> queryUnitRevocationRecord(PageQueryData <UnitRevocationListDto> pageQueryData, Integer queryType) {
    String userId = WebServiceUtils.getCurrentUserId();
    Pageable pageable = new PageRequest(pageQueryData.getPage() - 1,pageQueryData.getRows());
    // 查詢條件
    Map <String, String> searchTexts = pageQueryData.getSearchTexts();
    // 條件分頁功能
    Page <UnitRevocationRecord> pages = unitRevocationDao.findAll((root, query, cb) -> {
      List<Predicate> lstPredicates = new ArrayList <>();
      if(searchTexts != null){
        if(!CheckUtil.isNullorEmpty(searchTexts.get("unitId"))){
          lstPredicates.add(cb.equal(root.get("unitId"),searchTexts.get("unitId")));
        }
        if(!CheckUtil.isNullorEmpty(searchTexts.get("applicantId"))){
          lstPredicates.add(cb.equal(root.get("applicantId"),searchTexts.get("applyUnitId")));
        }
        if(!CheckUtil.isNullorEmpty(searchTexts.get("state"))){
          lstPredicates.add(cb.equal(root.get("state"),searchTexts.get("state")));
        }
      }
      if(queryType == 0){
        lstPredicates.add(cb.equal(root.get("applicantId"),userId));
      }else if(queryType == 1){
        lstPredicates.add(cb.notEqual(root.get("state"),EnumUnitRevocationState.NREPORT.getState()));
        lstPredicates.add(cb.notEqual(root.get("state"),EnumUnitRevocationState.CALLBACK.getState()));
      }
      Predicate[] arrayPredicates = new Predicate[lstPredicates.size()];
      return cb.and(lstPredicates.toArray(arrayPredicates));
    }, pageable);
    
    List <UnitRevocationRecord> content = pages.getContent();
    List <UnitRevocationListDto> records = new ArrayList <>();
    content.forEach(item -> {
      UnitRevocationListDto unitRevocationListDto = this.convertRevocation(queryType, item);
      records.add(unitRevocationListDto);
    });
    pageQueryData.setTotal((int) pages.getTotalElements());
    pageQueryData.setQueryList(records);
    return pageQueryData;
  }