Java 持久化/ElementCollection
JPA 2.0 定義了 ElementCollection 對映。它旨在處理幾種非標準關係對映。ElementCollection 可用於定義與 Embeddable 物件的 一對多 關係,或 Basic 值(例如 String 集合)。ElementCollection 也可以與 Map 結合使用來定義關係,其中鍵可以是任何型別的物件,而值是 Embeddable 物件或 Basic 值。
在 JPA 中,ElementCollection 關係透過 @ElementCollection 註解或 <element-collection> 元素定義。
ElementCollection 值始終儲存在單獨的表中。該表透過 @CollectionTable 註解或 <collection-table> 元素定義。CollectionTable 定義了表的 name 和 @JoinColumn 或 @JoinColumns (如果使用複合主鍵)。
ElementCollection 對映可用於定義 Embeddable 物件的集合。這不是 Embeddable 物件的典型用法,因為這些物件不會嵌入到源物件的表中,而是儲存在單獨的集合表中。這類似於 OneToMany,只是目標物件是 Embeddable 而不是 Entity。這允許輕鬆定義簡單物件的集合,而無需要求簡單物件定義 Id 或 ManyToOne 逆對映。ElementCollection 還可以覆蓋其集合的對映或表,因此您可以讓多個實體引用同一個 Embeddable 類,但每個實體將它們相關的物件儲存在單獨的表中。
使用 ElementCollection 而不是 OneToMany 的侷限性在於,目標物件無法獨立於其父物件進行查詢、持久化、合併。它們嚴格來說是私有擁有的(依賴)物件,與 Embedded 對映相同。ElementCollection 上沒有 cascade 選項,目標物件始終與其父物件一起持久化、合併、刪除。ElementCollection 仍然可以使用 fetch 型別,並且預設情況下為 LAZY,與其他集合對映相同。
EMPLOYEE(表)
| EMP_ID | F_NAME | L_NAME | SALARY |
| 1 | Bob | Way | 50000 |
| 2 | Joe | Smith | 35000 |
PHONE(表)
| OWNER_ID | TYPE | AREA_CODE | P_NUMBER |
| 1 | home | 613 | 792-0001 |
| 1 | work | 613 | 494-1234 |
| 2 | work | 416 | 892-0005 |
@Entity
public class Employee {
@Id
@Column(name="EMP_ID")
private long id;
...
@ElementCollection
@CollectionTable(
name="PHONE",
joinColumns=@JoinColumn(name="OWNER_ID")
)
private List<Phone> phones;
...
}
@Embeddable
public class Phone {
private String type;
private String areaCode;
@Column(name="P_NUMBER")
private String number;
...
}
<entity name="Employee" class="org.acme.Employee" access="FIELD">
<attributes>
<id name="id">
<column name="EMP_ID"/>
</id>
<element-collection name="phones">
<collection-table name="PHONE">
<join-column name="OWNER_ID"/>
</collection-table>
</element-collection>
</attributes>
</entity>
<embeddable name="Phone" class="org.acme.Phone" access="FIELD">
<attributes>
<basic name="number">
<column name="P_NUMBER"/>
</basic>
</attributes>
</embeddable>
ElementCollection 對映可用於定義 Basic 物件的集合。Basic 值儲存在單獨的集合表中。這類似於 OneToMany,只是目標是 Basic 值而不是 Entity。這允許輕鬆定義簡單值的集合,而無需為該值定義類。
ElementCollection 上沒有 cascade 選項,目標物件始終與其父物件一起持久化、合併、刪除。ElementCollection 仍然可以使用 fetch 型別,並且預設情況下為 LAZY,與其他集合對映相同。
EMPLOYEE(表)
| EMP_ID | F_NAME | L_NAME | SALARY |
| 1 | Bob | Way | 50000 |
| 2 | Joe | Smith | 35000 |
PHONE(表)
| OWNER_ID | PHONE_NUMBER |
| 1 | 613-792-0001 |
| 1 | 613-494-1234 |
| 2 | 416-892-0005 |
@Entity
public class Employee {
@Id
@Column(name="EMP_ID")
private long id;
...
@ElementCollection
@CollectionTable(
name="PHONE",
joinColumns=@JoinColumn(name="OWNER_ID")
)
@Column(name="PHONE_NUMBER")
private List<String> phones;
...
}
<entity name="Employee" class="org.acme.Employee" access="FIELD">
<attributes>
<id name="id">
<column name="EMP_ID" />
</id>
<element-collection name="phones" target-class="java.lang.String">
<column name="PHONE_NUMBER" />
<collection-table name="PHONE">
<join-column name="OWNER_ID" />
</collection-table>
</element-collection>
</attributes>
</entity>
- JPA 2.0 規範沒有提供定義
Embeddable中Id的方法。但是,為了刪除或更新ElementCollection對映的元素,通常需要一些唯一的鍵。否則,JPA 提供者將需要在每次更新時從Entity的CollectionTable中刪除所有內容,然後再插入值。因此,JPA 提供者很可能會假設Embeddable中所有欄位的組合與外部索引鍵(JoinColumn(s))組合是唯一的。然而,如果Embeddable很大或很複雜,這可能效率低下或不可行。
- 一些 JPA 提供者可能允許在
Embeddable中指定Id來解決此問題。請注意,在這種情況下,Id只需要在集合中是唯一的,而不是在表中是唯一的,因為外部索引鍵包含在內。一些 JPA 提供者也可能允許使用CollectionTable上的unique選項來實現這一點。否則,如果Embeddable很複雜,您可能需要將其改為Entity,並使用OneToMany代替。
