JPA(hibernate)一對多根據多的一方某屬性進行過濾查詢
我們經常會碰上某個欄位是集合元素(List,Set)的情況,並且我們要過濾出集合中包含某個或某些元素的資料。
譬如一個類User
/**
* 檢索人
*/
private Long userId;
/**
* 省、直轄市集合
*/
@ElementCollection
@CollectionTable
private List<String> provinces;
/**
* 市、區集合
*/
@ElementCollection
@CollectionTable
private List<String> cities;
/**
* 行業集合
*/
@ElementCollection
@CollectionTable
private List<Integer> vocations;
包含一個String型的集合,我們希望能查詢出province="1"或者"2"的User集合。
倘若使用Hql或者原生sql是比較簡單的,但是使用Criteria查詢就不那麼簡單了,尤其是當User中包含多個集合元素,並且查詢條件不確定時。
Jpa中Criteria用來構建複雜查詢,之前我的文章中(http://blog.csdn.net/tianyaleixiaowu/article/details/72876732)已經講過了如何構建動態條件查詢,裡面就有如何實現查詢集合元素中是否包含某元素的功能。
重點看一下那篇文章中的SimpleExpression.java,裡面的case IS_MEMBER,呼叫了CriteriaBuilder的isMember方法,該方法就能查詢出你的集合中是否包含某個元素。
請注意,我定義User類時,註解寫的是:@ElementCollection,對映的是基本型別不是一個javaBean類,所以無法使用表關聯的寫法如user.address.id=XXX,這樣的hibernate表關聯寫法。
那麼就需要使用isMember這樣的寫法(注意:需要匯入上面提到的那篇文章的幾個類,才能用下面的寫法):
Criteria<PtSearchCondition> criteria = new Criteria<>();
criteria.add(Restrictions.hasMembers("provinces", "110000", "120000"));
Page page = userRepository.findAll(criteria, new PageRequest(0, 10));
return page.getContent();
有個地方需要說明一下,@ElementCollection這個註解代表該屬性是一個集合屬性,它和one-to-many類似,但不是同一個東西,one-to-many註解的另一方也要是一個表,不能只是一個普通的基本型別的集合。
如果你的@ElementCollection註解的集合物件也是一個JavaBean,不是String或者Integer時,譬如User有多個Address,Set《Address》 addressSet,那麼Address類需要加@Embeddable註解,否則報錯。@Embeddable代表是一個嵌入式的物件,不是一個表對映物件。如果你用的是one-to-many,那麼Address就需要加上@Entity,代表需要對映到資料庫表。
下面還看查詢的問題:
如果你的屬性是一個物件的集合,並且是@ElementCollection註解的,那麼如何查詢呢?
很簡單,同樣還是使用
Criteria<PtSearchCondition> criteria = new Criteria<>();
criteria.add(Restrictions.hasMembers("address.name", "北京"));
Page page = userRepository.findAll(criteria, new PageRequest(0, 10));
在我的SimpleExpression.java中,有這樣一段程式碼來處理一對多的查詢
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
Path expression;
//此處是表關聯資料,注意僅限一層關聯,如user.address,
//查詢user的address集合中,address的name為某個值
if (fieldName.contains(".")) {
String[] names = StringUtils.split(fieldName, ".");
//獲取該屬性的型別,Set?List?Map?
expression = root.get(names[0]);
Class clazz = expression.getJavaType();
if (clazz.equals(Set.class)) {
SetJoin setJoin = root.joinSet(names[0]);
expression = setJoin.get(names[1]);
} else if (clazz.equals(List.class)) {
ListJoin listJoin = root.joinList(names[0]);
expression = listJoin.get(names[1]);
} else if (clazz.equals(Map.class)) {
MapJoin mapJoin = root.joinMap(names[0]);
expression = mapJoin.get(names[1]);
} else {
//是many to one時
expression = expression.get(names[1]);
}
} else {
//單表查詢
expression = root.get(fieldName);
}
裡面使用了SetJoin來完成對多的一方的某欄位的匹配查詢。
在Restrictions.java中,做了判斷多的一方是基本型別還是JavaBean的判斷:
/**
* 集合包含某幾個元素,譬如可以查詢User類中Set<String> set包含"ABC","bcd"的User集合,
* 或者查詢User中Set<Address>的Address的name為"北京"的所有User集合
* 集合可以為基本型別或者JavaBean,可以是one to many或者是@ElementCollection
* @param fieldName
* 列名
* @param value
* 集合
* @return
* expresssion
*/
public static LogicalExpression hasMembers(String fieldName, Object... value) {
SimpleExpression[] ses = new SimpleExpression[value.length];
int i = 0;
//集合中物件是基本型別,如Set<Long>,List<String>
Criterion.Operator operator = Criterion.Operator.IS_MEMBER;
//集合中物件是JavaBean
if (fieldName.contains(".")) {
operator = Criterion.Operator.EQ;
}
for (Object obj : value) {
ses[i] = new SimpleExpression(fieldName, obj, operator);
i++;
}
return new LogicalExpression(ses, Criterion.Operator.OR);
}
同理,如果是使用one to many來對映的1對多表關係,同樣可以使用上面的方法,寫法也完全相同。
Criteria<PtSearchCondition> criteria = new Criteria<>();
criteria.add(Restrictions.hasMembers("address.name", "北京"));
criteria.add(Restrictions.hasMembers("provinces", "110000", "120000"));
Page page = userRepository.findAll(criteria, new PageRequest(0, 10));
以上就能完成Jpa中1對多,根據多的一方的某屬性進行過濾匹配。
相關文章
- jpa一對多查詢
- Hibernate annotation, JPA如何對映多個屬性為unique
- spring data jpa關聯查詢(一對一、一對多、多對多)Spring
- jQuery根據多個屬性匹配元素jQuery
- spring data jpa 多對一聯表查詢Spring
- mysql like查詢 - 根據多個條件的模糊匹配查詢MySql
- 根據給定的字串,修改一個多層巢狀物件對應的屬性值字串巢狀物件
- gorm 關係一對一,一對多,多對多查詢GoORM
- SpringBoot整合Jpa對資料進行排序、分頁、條件查詢和過濾Spring Boot排序
- spring-data-jpa一對多、多對多雙向關聯,查詢操作的時候進入死迴圈問題Spring
- 關於Hibernate多層1對多關係查詢
- Spring data jpa 多表查詢(三:多對多關係動態條件查詢)Spring
- [增刪改查] 最規範的 JPA 一對多/多對一 CRUD 示例
- MyBatis 查詢資料時屬性中多對一的問題(多條資料對應一條資料)MyBatis
- ES查詢之查詢屬性過濾、結果高亮顯示
- goldegate根據實際要求進行對映到多個不同表Go
- sql根據多個欄位查詢重複記錄SQL
- mysql多條件過濾查詢之mysq高階查詢MySql
- Mysql利用Like支援根據匹配度進行查詢MySql
- [增刪改查] 最簡單的 JPA 一對多/多對一 CRUD 設計
- MySQL8 根據某屬性查詢欄位排名由自定義變數到rank()的變動MySql變數
- JPA(3) 表關聯關係(多對一、一對多、多對多、一對一)
- mybatis 根據多個id查詢資料 foreach標籤MyBatis
- SpringBoot Jpa多條件查詢Spring Boot
- Spring Data JPA 之 一對一,一對多,多對多 關係對映Spring
- linux 中根據檔案的大小進行檔案的查詢Linux
- 03 註解:多對多查詢
- #MyBatis多表查詢 #多對一、一對多的兩種實現方式 @FDDLCMyBatis
- 根據emp,dept,salgrade表進行的sql查詢語句(1)SQL
- mysql根據查詢結果批量更新多條資料(插入或更新)MySql
- Hibernate多對多示例
- 聊聊簡單又不簡單的圖上多跳過濾查詢
- JPA中對映關係詳細說明(一對多,多對一,一對一、多對多)、@JoinColumn、mappedBy說明APP
- 根據表查詢索引資訊索引
- 根據父表查詢子表
- 根據PID查詢 sqlSQL
- Stream流根據屬性去重
- 查詢某佔用資源較多的SQLSQL