首頁 >Java >java教程 >JAVA Spring Data JPA中的動態查詢程式碼詳解

JAVA Spring Data JPA中的動態查詢程式碼詳解

Y2J
Y2J原創
2017-04-25 16:42:562504瀏覽

spring Data JPA大大的簡化了我們持久層的開發,但是在實際應用中,我們還是需要動態查詢的。

例如,前端有多個條件,這些條件很多都是可選的,那麼後端的SQL,就應該是可以自訂的,在使用hibernate的時候,可以透過判斷條件來拼接SQL(HQL),當然,Spring Data JPA在簡化我們開發的同時,也是提供了支援的。

透過實作Criteria二實現的動態查詢,需要我們的Repo介面繼承JpaSpecificationExecutor接口,這是個泛型介面。

然後查詢的時候,傳入動態查詢參數,分頁參數等即可。

使用起來很簡單,不過為了知其所以然,先介紹一下Criteria API。

Criteria API

如果編譯器能夠對查詢執行語法正確性檢查,那麼對於 Java 物件而言該查詢就是型別安全的。 Java™Persistence API (JPA) 的 2.0 版本引入了 Criteria API,這個 API 首次將類型安全查詢引入到 Java 應用程式中,並為在執行時間動態地建構查詢提供一種機制。本文介紹如何使用 Criteria API 和與之密切相關的 Metamodel API 撰寫動態的型別安全查詢。

在使用Spring Data JPA的時候,只要我們的Repo層繼承JpaSpecificationExecutor介面就可以使用Specification進行動態查詢了,我們先看下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); 
}

可以看到提供了5個方法,方法的參數和回傳值已經很明顯的表達了其意圖。其中的參數,Pageable和Sort應該是比較簡單的,分別是分頁參數和排序參數,而重點就是Specification參數,先看下這個介面的定義:

public interface Specification<T> { 
 Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); 
}

其中就一個方法,回傳的是動態查詢的資料結構。


javax.persistence.criteria.Predicate toPredicate(javax.persistence.criteria.Root<T> root,
javax.persistence.criteria.CriteriaQuery<?> query,
javax.persistence.criteria.CriteriaBuilder cb);

這裡使用的都是Java EE中的規範,具體實作本人採用的是Hibernate,當然也可以選擇其他實作了JPA規範的資料持久層框架。
這裡需要再回過頭看看Criteria API中的一些東西:

Criteria 查詢是以元模型的概念為基礎的,元模型是為具體持久化單元的受管實體定義的,這些實體可以是實體類,嵌入類別或映射的父類。

CriteriaQuery介面:代表一個specific的頂層查詢對象,它包含查詢的各個部分,例如:select 、from、where、group by、order by等注意:CriteriaQuery物件只對實體類型或嵌入式類型的Criteria查詢起作用

Root介面:代表Criteria查詢的根對象,Criteria查詢的查詢根定義了實體類型,能為將來導航獲得想要的結果,它與SQL查詢中的FROM子句類似

1:Root實例是類型化的,並定義了查詢的FROM子句中能夠出現的型別。

2:查詢根實例能透過傳入一個實體類型給 AbstractQuery.from方法來獲得。

3:Criteria查詢,可以有多個查詢根。

4:AbstractQuery是CriteriaQuery 介面的父類,它提供得到查詢根的方法。 CriteriaBuilder介面:用來建構CritiaQuery的建構器物件Predicate:一個簡單或複雜的謂詞類型,其實就相當於條件或是條件組合

其中支援的方法非常強大,在下面給出一個範例,大家可以參考一下,同樣的,可以根據範例,自己可以寫出更為複雜的查詢:

#Repo介面:

public interface DevHREmpConstrastDao 
 extends JpaRepository<DevHREmpConstrast, Long>,JpaSpecificationExecutor<DevHREmpConstrast>

查詢實例1:

/** 
 * 条件查询时动态组装条件 
 */ 
private Specification<DevHREmpConstrast> where( 
  final String corg,final String name,final String type,final String date,final String checker){ 
 return new Specification<DevHREmpConstrast>() { 
  @Override 
  public Predicate toPredicate(Root<DevHREmpConstrast> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
   List<Predicate> predicates = new ArrayList<Predicate>(); 
   //机构 
   if(corg!=null&&!corg.equals("")){ 
    List<String> orgIds = organizationDao.findByName("%"+corg+"%"); 
    if(orgIds.size()>0&&orgIds.size()<1000) 
     predicates.add(root.<String>get("confirmOrgNo").in(orgIds));//confirmOrgNo 
   } 
   //名字 
   if(name!=null&&!name.equals("")){ 
    List<String> userIds = userDao.findByName(name); 
    if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
     predicates.add(root.<String>get("hrUserName").in(userIds)); 
   } 
   //类型 
   if(type!=null&&!type.equals("")) 
    predicates.add(cb.equal(root.<String>get("hrUpdateType"),type)); 
   //日期 
   if(date!=null&&!date.equals("")){ 
    //处理时间 
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 
    Date startDate; 
    Date endDate; 
    try { 
     startDate = format.parse(date); 
    } catch (ParseException e) { 
     startDate = new Date(946656000000L);//2000 01 01 
    } 
    endDate = startDate; 
    Calendar calendar = Calendar.getInstance() ; 
    calendar.setTime(endDate); 
    calendar.add(Calendar.DATE, 1); 
    endDate = calendar.getTime(); 
    calendar = null; 
    predicates.add(cb.between(root.<Date>get("insDate"),startDate,endDate)); 
   } 
   //审核人 
   if(checker!=null&&!checker.equals("")){ 
    List<String> userIds = userDao.findByName(checker); 
    if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
     predicates.add(root.<String>get("confirmUserId").in(userIds)); 
   } 
   return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
  } 
 }; 
}

查詢實例2:

/** 
 * 条件查询时动态组装条件 
 */ 
 private Specification<DevHREmpConstrast> where( 
   final String corg,final String name,final String type,final String date,final String checker){ 
  return new Specification<DevHREmpConstrast>() { 
   @Override 
   public Predicate toPredicate(Root<DevHREmpConstrast> root, CriteriaQuery<?> query, CriteriaBuilder cb) { 
    List<Predicate> predicates = new ArrayList<Predicate>(); 
    //机构 
    if(corg!=null&&!corg.equals("")){ 
     List<String> orgIds = organizationDao.findByName("%"+corg+"%"); 
     if(orgIds.size()>0&&orgIds.size()<1000) 
      predicates.add(root.<String>get("confirmOrgNo").in(orgIds));//confirmOrgNo 
    } 
    //名字 
    if(name!=null&&!name.equals("")){ 
     List<String> userIds = userDao.findByName(name); 
     if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
      predicates.add(root.<String>get("hrUserName").in(userIds)); 
    } 
    //类型 
    if(type!=null&&!type.equals("")) 
     predicates.add(cb.equal(root.<String>get("hrUpdateType"),type)); 
    //日期 
    if(date!=null&&!date.equals("")){ 
     //处理时间 
     SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 
     Date startDate; 
     Date endDate; 
     try { 
      startDate = format.parse(date); 
     } catch (ParseException e) { 
      startDate = new Date(946656000000L);//2000 01 01 
     } 
     endDate = startDate; 
     Calendar calendar = Calendar.getInstance() ; 
     calendar.setTime(endDate); 
     calendar.add(Calendar.DATE, 1); 
     endDate = calendar.getTime(); 
     calendar = null; 
     predicates.add(cb.between(root.<Date>get("insDate"),startDate,endDate)); 
    } 
    //审核人 
    if(checker!=null&&!checker.equals("")){ 
     List<String> userIds = userDao.findByName(checker); 
     if(userIds.size()>0&&userIds.size()<1000)//如果太多就不管了这个条件了 
      predicates.add(root.<String>get("confirmUserId").in(userIds)); 
    } 
    return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction(); 
   } 
  }; 
 }

然後呼叫dao層方法傳入where()方法傳回的參數即可。

以上是JAVA Spring Data JPA中的動態查詢程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn