JPA
Specifies the mapping of associations. It is applied to the owning side of an association.
Join table 通常應用於映射:
多對多
單向的一對多
雙向的多對一/一對多
單向的多對一
單向及雙向的一對一
單向 | 雙向 | |
---|---|---|
一對多 | 有 | 有 |
多對一 | 有 | 有 |
一對一 | 有 | 有 |
多對多 | 有 |
A join table is typically used in the mapping of many-to-many and unidirectional one-to-many associations. It may also be used to map bidirectional many-to-one/one-to-many associations, unidirectional many-to-one relationships, and one-to-one associations (both bidirectional and unidirectional).
When a join table is used in mapping a relationship with an embeddable class on the owning side of the relationship, the containing entity rather than the embeddable class is considered the owner of the relationship.
If the JoinTable annotation is missing, the default values of the annotation elements apply. The name of the join table is assumed to be the table names of the associated primary tables concatenated together (owning side first) using an underscore.
一個學生可以擁有多種課程
一個課程也可以有多個學生
如此一來就形成了多對多的關係
student
學生、course
課程為主要的表單course_rating
可以稱為中介表或是聯接表course_rating
裡不需要rating
這個欄位就可以使用,rating
的用途後面會再提到我們需在兩個 Entity 中各自加入一個 Collection 並且以 @ManytoMany annotation 設置關聯
在擁有者方(student.java),注意到這段
而在目標方(course.java),我們只需提供映射關係的字段名稱。
以學生-課程為例,學生要對課程做評分,沒辦法儲存在學生的表中,因為一個學生可以有多門課程,反過來說要存在課程中也不是一個好方法。
這時我們就可以在關係表(中介表)中加入屬性(欄位),跟上面的基礎多對多模型幾乎相同,只是多加了一個屬性 rating
由於我們將數據庫屬性映射到 JPA 中的 class 字段,因此我們需要為該仲介表創建一個新的 Entity。
不過因為我們的 primary key 是一個組合鍵,我們必須另外新增一個 class,來存放鍵的不同部分。
使用此複合類,我們可以對中介表建立一個 entity class 模型
此代碼與常規 entity 實現非常相似。但是,我們有一些主要區別:
接下來在 student 跟 course 的 repository層中各寫一個 method
再接著,我們就可以在 controller 層中去呼叫 repository 的 method
所以當我們到頁面上查詢學生 id=1 的時候,就應該要顯示出他擁有的兩門課程 國語 跟 英文
過程中碰到的問題(待解決):
一開始執行程式時會出現 stackOverFlowError 的錯誤
這是因為一個雙向多對多的關係,在使用 fetch = FetchType.EAGER 的時候,會形成無限遞迴,呼叫A程式的 Collection<Course>,而B程式中又會呼叫A的 Collection<Student>,此時我們可以在其中一個 entity 中的 Collection 加入一個 @JsonIgnore ,不過這樣一來,就只有查詢學生的時候可以得到課程,而課程沒辦法查到學生了。
Student.java
Course.java
@Fetch定義資料庫關聯
JOIN
: 使用JOIN
關聯資料表,可以載入 related entities, collections 或 joinsSELECT
:使用SELECT
關聯資料表,可以載入 related entities, collections 或 joinsSUBSELECT
:使用子查詢來關聯資料表,只適用 collectionsHibernate throws MultipleBagFetchException - cannot simultaneously fetch multiple bags
多對多的資料寫入 創建C 修改U
method 的參數中,我們直接帶入了@RequestParam(name = "courses") Set<Course> courses
,這樣一來我們在 setCourses時就直接 student.setCourses(courses);
直接帶入即可
if (null == fullName || fullName.isEmpty()) { fullName = Long.toHexString(new GregorianCalendar().getTimeInMillis()); }
這邊在做的只是沒有給予 fullName 參數的值時,會隨機產生一個值
最後直接回傳 studentRepository.saveAndFlush(student)
demomo結果:
如果對一個學生增加一個課程是沒有問題的
但如果是一個學生增加數個課程會出現這樣的錯誤
這時將 Course.java 裡
@ManyToMany 括號中的 cascade = CascadeType.ALL 拿掉就沒問題了,主要是因為 CasadeTyepe.merge
這個屬性所造成
解決辦法參考來源