Spring data jpa 多表查詢(三:多對多關係動態條件查詢)

我愛吃酥餅發表於2017-07-24

上一章說了,一對多關係,動態條件查詢,這章開始說多對多關係模型


1.A  和 B (n : n)意思就是多對多,下面開始在模型中,建立關係

@Entity

class A 

{

@Column("唯一性標識,主鍵等等")

String id;


@Column("name = name")

String name;


@ManyToMany(mappedBy="aList")

List<B> bList;

}


@Entity

class B

{

@Column("唯一性標識,主鍵等等")

String id;


@Column("name = name")

String name;



@ManyToMany()

@JoinTable(name="a2b" ,joinColumns=@JoinColumn(name="b_id"),inverseJoinColumns=@JoinColumn(name="a_id"))

List<A> aList;

}


建好之後,解釋下,:A 模型中定義了mappedBy,意思是,A 是 A和B多對多的維護段,新增,刪除,修改,一般針對A 模型操作即可,當然也可以從B,只不過,稍微複雜些,此處不再多說。

B 模型中,定義了 中間維護表,指定了表名叫 a2b,並且在 表中,定義了a_id ,b_id, 來標識 A和B多對多關係維護表。

前兩張動態條件查詢,也適用於現在,因此不再多謝,

只需要一條語句來表名他們之間的關係:

Join<A,B> BJoin = root.join(root.get("bList",JoinType.Left);


這條關係,就已經包含了,把a2b 中間表的查詢,包含在裡面,大家可以,junit時候,斷點檢視列印的sql語句


當然,我當時遇到的,是在這基礎上,還得加上一層關係,即,C -> A ->B  即:C 和 A 是一對多。A 和B 多對多、

建立的關係如下:

主體是C 

因此root 代表的就是C


Join<C,A> aJoin = root.join(root.get("aList"),JoinType.Left);

Join<A,B> bJoin = aJoin.join("bList",JoinType.Left);

此時,關係就建立好,想帶C 。A。B的引數都可以帶進來


root 接  C 的引數

aJoin 接 A 的引數

bJoin 接 B 的引數


再次宣告一點,JPA ,不支援右連線查詢,當然這只是我調研的結果,因為JPA 認為沒有父哪來的子,必須從左開始,當然除了內連線。


因此,如果某些業務 需要查詢從子開始,JPA 直接查詢不到,但是可以換個思路去解決。例如以下需求


更換下上面的模型關係


A ->B -> C

1->n ->n


針對A 傳入一個id,查出B 和 C,並且是分頁查詢,加 動態條件

對於我們來說,只要關係建立好了,動態條件也就好寫了。

一般分頁,針對 最小單元進行分頁,也就是我們的C 做分頁

條件如下:a_id 是固定的引數,其次B中的name,c中的name 都是 動態的


因此我的思路是這樣的:

1.根據a_id ,查出多個 B

2.根據多個B 查出 B和C 關聯表中的C中的id,

3.最後 把C 中的id 查出來作為條件帶入C中,即可查出 關聯的C


實現的虛擬碼如下:

Page<C> findC(Pageable pageable,ParamDTO dto ,String a_id)

{

此時主體是C,因此root代表的是C


//Specification ,此處省略,可以參考前兩章內容


//1.根據a_id 查出多個B

CriterQuery<B> bQuery = criteraBuilder.createQuery(B.class);

Root<B> root1 = bQuery.from(B.class);


predicateList.add(criteriaBuilder.equal(root1.get("a"),a_id));


//如果有B中的動態引數,即在這裡寫

if(null != bName)

{

predicateList.add(criteriaBuilder.equal(root1.get("name"),bName));

}


bQuery.where(criteriaBuilder.and(predicates.toArray(new Predicate[predicate.size()])));

//查出了B 的集合

List<B> bList = em.createQuery(bQuery).getResultList();


//上面的criteraBuilder,criteriaQuery,em, root,都已經省略,在上一章可以找到。


下面將List<B> 轉換下 B 的id


List<String> ids = new ArrayList<String>();

for(B b:bList)

 {

  ids.add(b.get(id))


這時候,再建立 B 和C 的關係

Join<C,B> bJoin = root.join("bList");

predicateList.add(bJoin.get("id").in(ids));


意思就是  B 和C 建立了 內連線,然後,B 的id 帶入,就查出了 C


這裡用到了 in  方法,不需要用到criterialBuilder, 到此,jpa的查詢,基本上結束,有問題可以留言


}


總結:JPA如果把模型關係理清,sql  的確不怎麼需要我們去維護,還是很方便的。還有JPA中的模型之間的懶載入,我還沒說,


下一章,開始 說說懶載入













相關文章