spring data jpa複雜多條件查詢

一.排序與分頁

// 排序
Direction direction = Direction.DESC;
//directionStr爲前端傳值,asc代表正序
if ("asc".equals(directionStr)) {
	direction = Direction.ASC;
}
//默認使用datetime字段進行排序
String sortProperty = "datetime";
//sortParam爲前端傳的排序字段
if (UtilValidate.isNotEmpty(sortParam)) {
	sortProperty = sortParam;
}
Sort sort = new Sort(direction, sortProperty);

// 分頁
// pageNumParam爲頁碼,默認爲0,pageSizeParam爲每頁條數
Pageable pageable = PageRequest.of(pageNumParam, pageSizeParam, sort);

注意:

如果想要按照外鍵關聯實體的某個屬性進行排序,sortProperty直接改爲對應的 “實體名.屬性名” 即可:

1.比如一個User實體對象,外鍵一對一關聯地址實體對象Address,如果希望可以通過地址對象的id字段排序,那麼sortProperty就應該傳 “address.id” 。

@Entity
@Table(name="t_user")
public class User{
	@Id
	private Long id;

	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name = "address_id")
	@NotFound(action=NotFoundAction.IGNORE)
	private Address address;
	
	/**
	 * 登錄名
	 */
	@Column
	private String username;

	/**
	 * 狀態
	 */
	@Column
	private Integer state;

	/**
	 * 所屬機構
	 */
	@ManyToOne(fetch=FetchType.EAGER)
	@JoinColumn(name = "department_id")
	@NotFound(action=NotFoundAction.IGNORE)
	private Department department;

	/**
	 * 註冊時間
	 */
	@Column
	private Long datetime;
}

2.項目使用的是oracle數據庫,使用這種寫法剛開始一直報錯,排查後發現是配置的oracle方言的問題,如果有同樣使用oracle數據庫的小夥伴需要注意下,以下是修改的相關配置項:

#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle9Dialect

二.複雜查詢

以下的複雜查詢包含了4種類型:

1.外鍵關聯查詢 — 標註1

2.或查詢 — 標註2

3.外鍵in查詢 — 標註3

4.id的in查詢 — 標註4

使用JPA進行復雜多條件查詢,一般都需要重寫JpaSpecificationExecutor接口中的方法:

public interface JpaSpecificationExecutor<T> {

    T findOne(Specification<T> spec);

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

    Page<T> findAll(Specification<T> spec, Pageable pageable);

    List<T> findAll(Specification<T> spec, Sort sort);

    long count(Specification<T> spec);
}

我們此處需要使用的是Page findAll(Specification spec, Pageable pageable)方法,所以要針對它進行重寫:

// 假設此處查詢的是用戶列表
return userRepository.findAll(new Specification() {
	@Override
	public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
		List<Predicate> pList = new ArrayList<Predicate>();
		Predicate[] ps = new Predicate[pList.size()];
		List<Predicate> stateList = new ArrayList<Predicate>();
		Predicate[] statePs = new Predicate[stateList.size()];
		
		// 查詢用戶表中未刪除的地址 (標註1)
		// 假設address是用戶表User中的外鍵關聯,存放地址信息,state爲0代表有效
		pList.add(cb.equal(root.join("address").get("state"), 0));
		
		//查詢狀態爲10-未審覈或0-已審覈狀態的用戶 (標註2)
		stateList.add(cb.equal(root.get("state"), 0));
		stateList.add(cb.equal(root.get("state"),10));
		pList.add(cb.or(stateList.toArray(statePs)));
		
		// 時間查詢
		pList.add(cb.between(root.get("datetime"), start, end));
				
		// 機構查詢 (標註3)
		if (UtilValidate.isNotEmpty(departsStr)) {
			Predicate pDepart = inQuery(departsStr, "department", cb, root);
			pList.add(pDepart);
		}
			
		query.where(pList.toArray(ps));
		return null;
	}
}, pageable);

以下爲使用到的外鍵關聯in查詢的方法:

public Predicate inQuery(String entityIds, String entityName, CriteriaBuilder cb, Root root) {
	List<Predicate> list = new ArrayList<>();
	String[] ids = entityIds.split(",");
	if (ids != null && ids.length > 0) {
		In<Object> in = cb.in(root.join(entityName).get("id"));
		for (String id : ids) {
			Long idNum = Long.parseLong(id);
			in.value(idNum);
		}
		list.add(in);
	}

	Predicate[] p = new Predicate[list.size()];
	return cb.and(list.toArray(p));
}

如果希望進行id的in查詢,只需把root.join(entityName).get(“id”)改爲root.get(“id”)即可(標註4)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章