溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用JPA怎么實現(xiàn)多表復(fù)雜查詢

發(fā)布時間:2021-07-22 16:23:43 來源:億速云 閱讀:360 作者:Leah 欄目:編程語言

使用JPA怎么實現(xiàn)多表復(fù)雜查詢,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

1. 名字2. ID3. 手機號這是一個單表的多條件復(fù)雜查詢,由于是在幾個屬性中進(jìn)行篩選,其中的屬性的個數(shù)不知道有多少個,所以只需要利用Specification 查詢就可以很方便的實現(xiàn)這個需求。 下面請看代碼:場景:頁面上通過條件篩選,查詢用戶列表

這里有3個條件 在頁面上我設(shè)置的id分別為searchName,searchId,searchMobile。 由于這個是user表 所以userRepository 繼承JpaSpecificationExecutor接口,隨后我創(chuàng)建了一個封裝條件的類

public class PageParam<T> {  private Integer pageSize = 10;  private Integer pageNumber = 1;  private String searchName;  private String searchMobile;  private String searchId;}

由于我這個方法是直接分頁的 所以pageNumber 和pageSize 也可以直接寫入到這個類中,用于方便接收參數(shù),主要是對下面3個參數(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));  };};

這里因為都是一個表,所以只要root.get(‘N ‘)這個N對應(yīng)所要查的 屬性的名字就好,屬性名 屬性名 重要的事情說三遍。再接下來看一組多表的查詢

栗子2:

這里有4張表

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 為條件查詢出滿足條件的living。

public class PageParam<Living> {  private Integer pageSize = 10;  private Integer pageNumber = 1;  private Sex sex;  private ActorType actortype;  private Long cityid;

首先我還是封裝了這樣一個類,但是這里的泛型 我是直接給到了想要的查詢結(jié)果的泛型,接下來 因為這里涉及到了一個 多表的查詢 所以上面的單表查詢的例子 已經(jīng)不適合這個查詢了,但是Criteria 的join方法 給我們提供了一個模式

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));  };};

這里是我對條件進(jìn)行的封裝。jpa 的多條件查詢 主要是根據(jù)Criteria 為我們提供的方法封裝條件,然后根據(jù) 給條件定義的位置,再生成sql語句,之后完成查詢。

不得不說的地方,在這個多表的查詢中以下面這句為例

Join<UserDetail, Living> join = root.join("actor", JoinType.LEFT);list.add(cb.equal(join.get("userDetail").get("sex"), sex ));

jointype.LEFT主要是說最終的這個屬性 是在哪個表中, 而前面的 “actor” 則表示 從living表中 查詢的 第一步的查詢,比如我給出的例子 是要查詢出 living 中的 actor 然后是actor 中的userdetail 之后才是 userdetail中的 sex屬性 所以下面的join.get(“userDetail”).get(“sex”) ,這里就是get出相應(yīng)的屬性,一直到你得到想要的屬性為止。 接下來的兩個屬性 也同理,許多人多jpa 有很大的誤解,認(rèn)為jpa 的多表,多條件復(fù)雜查詢,不如mybatis的查詢,在之前我也是這么覺得,但自從通過jpa 實現(xiàn)了這個多表多條件的復(fù)雜查詢之后,我覺得hibernate的復(fù)雜查詢 不遜于mybatis ,尤其是對sql 語句不是很精通的 碼農(nóng),雖然hibernate的門檻較高可jpa 恰恰降低了hibernate 所需要的門檻,希望大家可以通過我的經(jīng)驗,更方便的與數(shù)據(jù)庫進(jìn)行交互。

看完上述內(nèi)容,你們掌握使用JPA怎么實現(xiàn)多表復(fù)雜查詢的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

jpa
AI