更新時(shí)間:2022-07-20 05:50:01 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽2086次
JPA多表查詢的方法有哪些?動(dòng)力節(jié)點(diǎn)小編來(lái)告訴大家。
使用實(shí)體類(lèi) User 中的多個(gè)屬性進(jìn)行過(guò)濾。
1.名稱
2.身份證
3.手機(jī)號(hào)碼
這是一個(gè)單表的多條件復(fù)雜查詢。因?yàn)槭窃诙鄠€(gè)屬性中過(guò)濾的,其中屬性的個(gè)數(shù)不知道有多少,所以只用規(guī)范查詢就可以很方便的實(shí)現(xiàn)這個(gè)需求。見(jiàn)下面代碼:
場(chǎng)景:在頁(yè)面上通過(guò)條件過(guò)濾查詢用戶列表
頁(yè)面上有三個(gè)條件設(shè)置了id為searchName、searchId和searchMobile。因?yàn)檫@是user表,所以u(píng)serRepository繼承了JpaSpecificationExecutor接口,然后我創(chuàng)建了一個(gè)封裝條件的類(lèi)。
public class PageParam<T> {
private Integer pageSize = 10;
private Integer pageNumber = 1;
private String searchName;
private String searchMobile;
private String searchId;
}
由于這個(gè)方法是直接分頁(yè)的,pageNumber和pageSize也可以直接寫(xiě)到這個(gè)類(lèi)中,方便參數(shù)的接收,主要封裝了以下三個(gè)參數(shù)。
Specification<T> specification = new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
if (StringUtils.isNotBlank(searchName)) {
list.add(cb.like(root.get("name").as(String.class), "%" + searchName + "%"));
}
if (StringUtils.isNotBlank(searchId)) {
list.add(cb.equal(root.get("id").as(Long.class), searchId));
}
if (StringUtils.isNotBlank(searchMobile)) {
list.add(cb.like(root.get("mobile").as(String.class), "%" + searchMobile + "%"));
}
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
};
};
因?yàn)檫@里都是一張表,只要root.get('N') N對(duì)應(yīng)要檢查的屬性名,屬性名重要的事情說(shuō)三遍。
接下來(lái)我們來(lái)看一組多表查詢
這里有四張桌子。
public class Living {
Long id;
@ManyToOne
@JsonIgnore
@JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT))
public Actor actor;
@ManyToOne
@JsonIgnore
@JoinColumn(name = "regionId", foreignKey = @ForeignKey(name = "none", value =ConstraintMode.NO_CONSTRAINT))
public Region region;
}
public class Actor {
Long id;
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "actorId")
@org.hibernate.annotations.ForeignKey(name = "none")
List<Living> livings = new ArrayList<>();
@OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@org.hibernate.annotations.ForeignKey(name = "none")
@JoinColumn(name = "userDetailId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
UserDetail userDetail;
@Column(nullable = false)
@Enumerated(value = EnumType.ORDINAL)
ActorType actorType = ActorType.A;
public enum ActorType{
A,B,C
}
}
public class UserDetail {
Long id;
@OneToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@org.hibernate.annotations.ForeignKey(name = "none")
@JoinColumn(name = "actorId", foreignKey = @ForeignKey(name = "none", value = ConstraintMode.NO_CONSTRAINT))
Actor actor;
String truename;
}
public class Region {
Long id;
String name;
@OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "regionId")
@org.hibernate.annotations.ForeignKey(name = "none")
List<Living> Livings;
}
現(xiàn)在我們需要根據(jù)userdetai的sex actor的actortype和region的id來(lái)查詢符合條件的live。
public class PageParam<Living> {
private Integer pageSize = 10;
private Integer pageNumber = 1;
private Sex sex;
private ActorType actortype;
private Long cityid;
首先,我封裝了這樣一個(gè)類(lèi),但是我把泛型類(lèi)型直接賦予了想要的查詢結(jié)果。接下來(lái)因?yàn)樯婕暗蕉啾聿樵儯陨厦鎲伪聿樵兊睦右呀?jīng)不適合這個(gè)查詢了,但是Criteria的join方法為我們提供了一個(gè)方法。
Specification<Living> specification = new Specification<Living>() {
@Override
public Predicate toPredicate(Root<Living> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
if (null!=sex) {
Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("userDetail").get("sex"), sex ));
}
if (null!=actortype) {
Join<Actor, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("actorType"), actortype));
}
if (null!=cityid) {
Join<Region, Living> join = root.join("region", JoinType.LEFT);
list.add(cb.equal(join.get("id"), cityid));
}
//Join<A, B> join = root.join("bs", JoinType.LEFT);
//list.add(cb.equal(join.get("c").get("id"), id));
Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p));
};
};
jpa的多條件查詢主要是根據(jù)Criteria提供的方法對(duì)條件進(jìn)行封裝,然后根據(jù)為條件定義的位置重新生成sql語(yǔ)句,然后完成查詢。
不得不說(shuō)的是,在這個(gè)多表查詢中,以下面這句話為例。
Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);
list.add(cb.equal(join.get("userDetail").get("sex"), sex ));
LEFT主要是指最終屬性在哪個(gè)表,而前面的“actor”代表從活表查詢的第一步。比如我給出的例子是查詢living中的actor,然后在userdetail中的sex屬性之前查詢actor中的user表。join.get("userDetail")。get("sex"),這里是取出對(duì)應(yīng)的屬性,直到得到想要的屬性。接下來(lái)的兩個(gè)屬性是一樣的。
很多人對(duì)jpa有很大的誤解。他們認(rèn)為jpa的多表多條件復(fù)雜查詢不如mybatis的查詢。如果大家對(duì)此感興趣,還可以了解一下什么是JPA框架,希望對(duì)大家的學(xué)習(xí)能夠有所幫助。
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743