首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Hibernate @Embeddable 與 <component> 映射詳解:組件模式實現值類型復用

     編輯:Java 綜合教學

什麼是組件?

組件** 是一種**值類型**,不具備獨立標識符(ID),生命週期完全依賴於擁有它的實體。資料庫層面,組件的字段直接扁平化映射到擁有實體的表中。**適用場景**:地址、姓名、金額幣別、時間區間等可復用的值對象。

註解映射

核心註解

  • @Embeddable:標記組件類(如 Address)。
  • @Embedded:在實體中引用組件(如 Person.homeAddress)。
  • @AttributeOverride / @AttributeOverrides:覆蓋組件字段的列映射(列名、類型等)。

基本範例

@Embeddable
public class Address {
    private String city;
    private String street;
    private String zipCode;
    // getters/setters
}

@Entity
public class Person {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @Embedded
    private Address homeAddress;  // 直接扁平化到 person 表

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "work_city")),
        @AttributeOverride(name = "street", column = @Column(name = "work_street")),
        @AttributeOverride(name = "zipCode", column = @Column(name = "work_zip"))
    })
    private Address workAddress;  // 同類型組件第二次使用,必須覆蓋列名
}

嵌套組件與關聯覆蓋

@Embeddable
public class Address {
    private String city;
    @Embedded private Country country;  // 嵌套組件
}

@Entity
public class Person {
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "home_city")),
        @AttributeOverride(name = "country.name", column = @Column(name = "home_country_name")), // 使用點號路徑
        @AttributeOverride(name = "country.isoCode", column = @Column(name = "home_country_iso"))
    })
    private Address homeAddress;
}

注意:JPA 標準不支援多層嵌套覆蓋,Hibernate 透過點號路徑(country.name)擴充支援。

關聯映射在組件中

@Embeddable
public class OrderItem {
    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;  // 組件中可持有關聯
    private int quantity;
    private BigDecimal price;
}

XML 映射

核心元素

  • <component name="propertyName" class="ComponentClass">
  • <property name="field" column="COL_NAME"/>
  • <parent name="owningEntityRef"/>:組件反向引用擁有實體(罕用)。

基本範例

<class name="Person" table="person">
    <id name="id" column="pid"><generator class="native"/></id>
    <property name="name"/>
    <component name="homeAddress" class="Address">
        <property name="city" column="home_city"/>
        <property name="street" column="home_street"/>
        <property name="zipCode" column="home_zip"/>
    </component>
    <component name="workAddress" class="Address">
        <property name="city" column="work_city"/>
        <property name="street" column="work_street"/>
        <property name="zipCode" column="work_zip"/>
    </component>
</class>

集合中的組件

<set name="addresses" table="person_addresses">
    <key column="person_id"/>
    <composite-element class="Address">
        <property name="city"/>
        <property name="street"/>
    </composite-element>
</set>

關鍵:Set 要求組件正確實現 equals()/hashCode();組件不可包含集合,需用 <nested-composite-element> 或改為一對多實體映射。

組件作為 Map Key / Composite ID

  • <composite-map-key class="Address">:組件作 Map 鍵,需實現 equals/hashCode。
  • <composite-id name="id" class="OrderLineId">:組件作複合主鍵,類必須實現 Serializable + equals/hashCode。

動態組件

<dynamic-component name="attrs"> 映射 Map<String, Object>,部署期通過修改映射文件動態增減屬性,無需改代碼。運行期可透過 Configuration 對象操作元模型。

完整實戰範例(註解版)

@Entity
public class Husband {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @Embedded
    private Wife wife;  // Wife 類無註解,Hibernate 自動檢測 @Embeddable
}

@Embeddable  // 必須加,否則視為實體關聯
public class Wife {
    private String wifeId;
    private String wifeName;
    private String age;
    // getters/setters
}

// 測試
@Test
public void testSchemaExport() {
    new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
}
// 生成表 husband:id, name, wifeId, wifeName, age

避坑指南

坑點後果解決
組件類漏加 @EmbeddableHibernate 視為實體關聯,產生外鍵、獨立表必加 @Embeddable
同實體引用兩次相同組件類未覆蓋列列名衝突、啟動報錯用 @AttributeOverride 區分列名
組件用於 Set 未實現 equals/hashCode去重失效、刪除異常基於所有字段實現 equals/hashCode
組件包含集合映射不支援改用一對多實體或 <nested-composite-element>

總結

組件映射實現**細粒度對象模型**,消除「貧血模型」中大量 getter/setter 的原始類型字段,提升領域模型表達力。註解映射更簡潔,XML 映射適合舊專案或需外部化配置場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved