跳轉到內容

Java 持久化/多對一

來自華夏公益教科書,開放的書,開放的世界

多對一

[編輯 | 編輯原始碼]

Java 中的 多對一 關係是指源物件有一個屬性引用另一個物件,即目標物件。例如典型的 Java 案例,一個物件持有對另一個物件的引用。多對一 關係可以是單向的。但是,目標物件通常具有指向源物件的逆關係。這將是目標物件中的 一對多 關係規範。Java 和 JPA 中的所有關係都是單向的,也就是說,如果源物件引用目標物件,則不能保證目標物件也與源物件有關係。這與關係資料庫不同,在關係資料庫中,關係透過外部索引鍵和查詢來定義,以便始終存在反向查詢。

在 JPA 中,多對一 關係透過 @ManyToOne 註解或 <many-to-one> 元素指定。@ManyToOne 註解通常伴隨 @JoinColumn 註解。@JoinColumn 註解指定了關係如何對映到資料庫(在資料庫中表示)。@JoinColumn 定義了源物件中用於查詢(連線)目標物件的外部鍵列名稱(@JoinColumn(name = "..."))。

如果在目標物件中指定了反向 一對多 關係,那麼目標物件中的 @OneToMany 註解必須包含 mappedBy 屬性來定義這個反向關係。

JPA 還定義了 一對一 關係,它類似於 多對一 關係,除了反向關係(如果定義了的話)是一個 一對一 關係。JPA 中 一對一多對一 關係的主要區別在於,多對一 始終包含從源物件表的外部鍵到目標物件表的外部鍵,而 一對一 關係的外部鍵可能位於源物件表或目標物件表中。

多對一 關係資料庫示例

[編輯 | 編輯原始碼]

員工(表)

員工 ID 姓名 姓氏 薪資 經理 ID
1 鮑勃 50000 2
2 莎拉 史密斯 75000

電話(表)

ID 型別 區號 電話號碼 所有者 ID
1 家庭 613 792-0000 1
2 工作 613 896-1234 1
3 工作 416 123-4444 2

多對一 關係註解示例

[編輯 | 編輯原始碼]
@Entity
public class Phone {
  @Id
  private long id;
  ...
  // Specifies the PHONE table does not contain an owner column, but 
  // an OWNER_ID column with a foreign key. And creates a join to
  // lazily fetch the owner
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="OWNER_ID")
  private Employee owner;
  ...
}

// Specification of the reverse OneToMany relationship in Employee
@Entity
public class Employee {
  @Id
  private long emp_id;
  ...
  // The 'mappedBy = "owner"' attribute specifies that
  // the 'private Employee owner;' field in Phone owns the
  // relationship (i.e. contains the foreign key for the query to
  // find all phones for an employee.)
  @OneToMany(mappedBy = "owner")
  private List<Phone> phones;
  ...

多對一 關係 XML 示例

[編輯 | 編輯原始碼]
<entity name="Phone" class="org.acme.Phone" access="FIELD">
    <attributes>
        <id name="id"/>
        <many-to-one name="owner" fetch="LAZY">
            <join-column name="OWNER_ID"/>
        </many-to-one>
    </attributes>
</entity>

另請參閱

[編輯 | 編輯原始碼]

常見問題

[編輯 | 編輯原始碼]
外部索引鍵也是主鍵的一部分。
[編輯 | 編輯原始碼]
參見 透過一對一關係生成主鍵.
外部索引鍵也對映為基本型別。
[編輯 | 編輯原始碼]
如果你在兩個不同的對映中使用相同的欄位,通常需要使用 insertable, updatable = false 使其中一個欄位變為只讀。
參見 目標外部索引鍵、主鍵連線列、級聯主鍵.
插入時的約束錯誤。
[編輯 | 編輯原始碼]
這通常是因為你在 一對一 關係中錯誤地映射了外部索引鍵。
參見 目標外部索引鍵、主鍵連線列、級聯主鍵.
如果你的 JPA 提供程式不支援引用完整性,或者無法解析雙向約束,也會發生這種情況。在這種情況下,你可能需要移除約束,或者使用 EntityManager flush() 來確保物件寫入的順序。
外部索引鍵值為空
[編輯 | 編輯原始碼]
確保你設定了物件的 一對一 值,如果 一對一 是雙向 一對多 關係的一部分,確保你在將物件新增到 一對多 中時設定了物件的 一對一,JPA 不會為你維護雙向關係。
還要檢查你是否正確定義了 JoinColumn,確保你沒有設定 insertable, updateable = false 或使用 PrimaryKeyJoinColumn

目標外部索引鍵、主鍵連線列、級聯主鍵

[編輯 | 編輯原始碼]

在複雜的資料模型中,如果外部索引鍵/JoinColumn 與其他 多對一Basic 對映共享,則可能需要使用目標外部索引鍵或只讀 JoinColumn 來對映 多對一

參見 目標外部索引鍵、主鍵連線列、級聯主鍵

華夏公益教科書