hibernate的component使用

来源:http://www.cnblogs.com/flab/archive/2016/04/20/5414957.html
-Advertisement-
Play Games

hibernate的Component,即組件,表示2個類之間的關係,即其中1個類可以作為另一個類的組件來使用。 1.先來看下annotation中關於component的API 2.2.2.3. 嵌入式對象(又名組件) 2.2.2.3. 嵌入式對象(又名組件) 2.2.2.3. 嵌入式對象(又名組 ...


hibernate的Component,即組件,表示2個類之間的關係,即其中1個類可以作為另一個類的組件來使用。

1.先來看下annotation中關於component的API

2.2.2.3. 嵌入式對象(又名組件)

 

在實體中可以定義一個嵌入式組件(embedded component), 甚至覆蓋該實體中原有的列映射. 組件類必須在類一級定義@Embeddable註解. 在特定的實體的關聯屬性上使用@Embedded@AttributeOverride註解可以覆蓋該屬性對應的嵌入式對象的列映射:

@Entity
public class Person implements Serializable {

    // Persistent component using defaults
    Address homeAddress;

    @Embedded
    @AttributeOverrides( {
            @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
            @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
    } )
    Country bornIn;
    ...
}
            
@Embeddable
public class Address implements Serializable {
    String city;
    Country nationality; //no overriding here
}
            
@Embeddable
public class Country implements Serializable {
    private String iso2;
    @Column(name="countryName") private String name;

    public String getIso2() { return iso2; }
    public void setIso2(String iso2) { this.iso2 = iso2; }

    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    ...
}
            

嵌入式對象繼承其所屬實體中定義的訪問類型 (註意:這可以通過使用Hibernate提供的@AccessType註解來覆蓋原有值)(請參考 Hibernate Annotation Extensions).

在上面的例子中,實體bean Person 有兩個組件屬性, 分別是homeAddressbornIn. 我們可以看到homeAddress 屬性並沒有註解. 但是Hibernate自動檢測其對應的Address類中的@Embeddable註解, 並將其看作一個持久化組件.對於Country中已映射的屬性, 則使用@Embedded@AttributeOverride 註解來覆蓋原來映射的列名. 正如你所看到的, Address對象中還內嵌了Country對象, 這裡和homeAddress一樣使用了Hibernate和EJB3自動檢測機制. 目前EJB3規範還不支持覆蓋多層嵌套(即嵌入式對象中還包括其他嵌入式對象)的列映射. 不過Hibernate通過在表達式中使用"."符號表達式提供了對此特征的支持.

    @Embedded
    @AttributeOverrides( {
            @AttributeOverride(name="city", column = @Column(name="fld_city") ),
            @AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),
            @AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )
            //nationality columns in homeAddress are overridden
    } )
    Address homeAddress;

Hibernate註解支持很多EJB3規範中沒有明確定義的特性. 例如,可以在嵌入式對象上添加 @MappedSuperclass註解, 這樣可以將其父類的屬性持久(詳情請查閱@MappedSuperclass).

Hibernate現在支持在嵌入式對象中使用關聯註解(如@*ToOne@*ToMany). 而EJB3規範尚不支持這樣的用法。你可以使用 @AssociationOverride註解來覆寫關聯列.

在同一個實體中使用兩個同類型的嵌入對象, 其預設列名是無效的:至少要對其中一個進行明確聲明. Hibernate在這方面走在了EJB3規範的前面, Hibernate提供了NamingStrategy, 在使用Hibernate時, 通過NamingStrategy你可以對預設的機制進行擴展. DefaultComponentSafeNamingStrategy 在預設的EJB3NamingStrategy上進行了小小的提升, 允許在同一實體中使用兩個同類型的嵌入對象而無須額外的聲明.

 

2.再來看下xml中關於component的API

第 8 章 組件(Component)映射

8.1. 依賴對象(Dependent objects)
8.2. 在集合中出現的依賴對象 (Collections of dependent objects)
8.3. 組件作為Map的索引(Components as Map indices )
8.4. 組件作為聯合標識符(Components as composite identifiers)
8.5. 動態組件 (Dynamic components)

The notion of a component is re-used in several different contexts and purposes throughout Hibernate.

8.1. 依賴對象(Dependent objects)

A component is a contained object that is persisted as a value type and not an entity reference. The term "component" refers to the object-oriented notion of composition and not to architecture-level components. For example, you can model a person like this:

public class Person {
    private java.util.Date birthday;
    private Name name;
    private String key;
    public String getKey() {
        return key;
    }
    private void setKey(String key) {
        this.key=key;
    }
    public java.util.Date getBirthday() {
        return birthday;
    }
    public void setBirthday(java.util.Date birthday) {
        this.birthday = birthday;
    }
    public Name getName() {
        return name;
    }
    public void setName(Name name) {
        this.name = name;
    }
    ......
    ......
}
public class Name {
    char initial;
    String first;
    String last;
    public String getFirst() {
        return first;
    }
    void setFirst(String first) {
        this.first = first;
    }
    public String getLast() {
        return last;
    }
    void setLast(String last) {
        this.last = last;
    }
    public char getInitial() {
        return initial;
    }
    void setInitial(char initial) {
        this.initial = initial;
    }
}

Now Name can be persisted as a component of PersonName defines getter and setter methods for its persistent properties, but it does not need to declare any interfaces or identifier properties.

Our Hibernate mapping would look like this:

<class name="eg.Person" table="person">
    <id name="Key" column="pid" type="string">
        <generator class="uuid"/>
    </id>
    <property name="birthday" type="date"/>
    <component name="Name" class="eg.Name"> <!-- class attribute optional -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </component>
</class>

人員(Person)表中將包括pidbirthdayinitialfirst和 last等欄位。

Like value types, components do not support shared references. In other words, two persons could have the same name, but the two person objects would contain two independent name objects that were only "the same" by value. The null value semantics of a component are ad hoc. When reloading the containing object, Hibernate will assume that if all component columns are null, then the entire component is null. This is suitable for most purposes.

The properties of a component can be of any Hibernate type (collections, many-to-one associations, other components, etc). Nested components should not be considered an exotic usage. Hibernate is intended to support a fine-grained object model.

<component> 元素還允許有 <parent>子元素,用來表明component類中的一個屬性是指向包含它的實體的引用。

<class name="eg.Person" table="person">
    <id name="Key" column="pid" type="string">
        <generator class="uuid"/>
    </id>
    <property name="birthday" type="date"/>
    <component name="Name" class="eg.Name" unique="true">
        <parent name="namedPerson"/> <!-- reference back to the Person -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </component>
</class>

8.2. 在集合中出現的依賴對象 (Collections of dependent objects)

Collections of components are supported (e.g. an array of type Name). Declare your component collection by replacing the <element> tag with a <composite-element> tag:

<set name="someNames" table="some_names" lazy="true">
    <key column="id"/>
    <composite-element class="eg.Name"> <!-- class attribute required -->
        <property name="initial"/>
        <property name="first"/>
        <property name="last"/>
    </composite-element>
</set>

重要

If you define a Set of composite elements, it is important to implement equals() and hashCode()correctly.

Composite elements can contain components but not collections. If your composite element contains components, use the <nested-composite-element> tag. This case is a collection of components which themselves have components. You may want to consider if a one-to-many association is more appropriate. Remodel the composite element as an entity, but be aware that even though the Java model is the same, the relational model and persistence semantics are still slightly different.

A composite element mapping does not support null-able properties if you are using a <set>. There is no separate primary key column in the composite element table. Hibernate uses each column's value to identify a record when deleting objects, which is not possible with null values. You have to either use only not-null properties in a composite-element or choose a <list><map><bag> or <idbag>.

A special case of a composite element is a composite element with a nested <many-to-one> element. This mapping allows you to map extra columns of a many-to-many association table to the composite element class. The following is a many-to-many association from Order to Item, where purchaseDateprice andquantity are properties of the association:

<class name="eg.Order" .... >
    ....
    <set name="purchasedItems" table="purchase_items" lazy="true">
        <key column="order_id">
        <composite-element class="eg.Purchase">
            <property name="purchaseDate"/>
            <property name="price"/>
            <property name="quantity"/>
            <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
        </composite-element>
    </set>
</class>

There cannot be a reference to the purchase on the other side for bidirectional association navigation. Components are value types and do not allow shared references. A single Purchase can be in the set of anOrder, but it cannot be referenced by the Item at the same time.

其實組合元素的這個用法可以擴展到三重或多重關聯:

<class name="eg.Order" .... >
    ....
    <set name="purchasedItems" table="purchase_items" lazy="true">
        <key column="order_id">
        <composite-element class="eg.OrderLine">
            <many-to-one name="purchaseDetails class="eg.Purchase"/>
            <many-to-one name="item" class="eg.Item"/>
        </composite-element>
    </set>
</class>

Composite elements can appear in queries using the same syntax as associations to other entities.

8.3. 組件作為Map的索引(Components as Map indices )

The <composite-map-key> element allows you to map a component class as the key of a Map. Ensure that you override hashCode() and equals() correctly on the component class.

8.4. 組件作為聯合標識符(Components as composite identifiers)

You can use a component as an identifier of an entity class. Your component class must satisfy certain requirements:

  • 它必須實現java.io.Serializable介面

  • It must re-implement equals() and hashCode() consistently with the database's notion of composite key equality.

Note

In Hibernate3, although the second requirement is not an absolutely hard requirement of Hibernate, it is recommended.

You cannot use an IdentifierGenerator to generate composite keys. Instead the application must assign its own identifiers.

Use the <composite-id> tag, with nested <key-property> elements, in place of the usual <id> declaration. For example, the OrderLine class has a primary key that depends upon the (composite) primary key of Order.

<class name="OrderLine">
    
    <composite-id name="id" class="OrderLineId">
        <key-property name="lineId"/>
        <key-property name="orderId"/>
        <key-property name="customerId"/>
    </composite-id>
    
    <property name="name"/>
    
    <many-to-one name="order" class="Order"
            insert="false" update="false">
        <column name="orderId"/>
        <column name="customerId"/>
    </many-to-one>
    ....
    
</class>

Any foreign keys referencing the OrderLine table are now composite. Declare this in your mappings for other classes. An association to OrderLine is mapped like this:

<many-to-one name="orderLine" class="OrderLine">
<!-- the "class" attribute is optional, as usual -->
    <column name="lineId"/>
    <column name="orderId"/>
    <column name="customerId"/>
</many-to-one>

提示

The column element is an alternative to the column attribute everywhere. Using the columnelement just gives more declaration options, which are mostly useful when utilizing hbm2ddl

指向OrderLine多對多關聯也使用聯合外鍵:

<set name="undeliveredOrderLines">
    <key column name="warehouseId"/>
    <many-to-many class="OrderLine">
        <column name="lineId"/>
        <column name="orderId"/>
        <column name="customerId"/>
    </many-to-many>
</set>

Order中,OrderLine的集合則是這樣:

<set name="orderLines" inverse="true">
    <key>
        <column name="orderId"/>
        <column name="customerId"/>
    </key>
    <one-to-many class="OrderLine"/>
</set>

The <one-to-many> element declares no columns.

假若OrderLine本身擁有一個集合,它也具有組合外鍵。

<class name="OrderLine">
    ....
    ....
    <list name="deliveryAttempts">
        <key>   <!-- a collection inherits the composite key type -->
            <column name="lineId"/>
            <column name="orderId"/>
            <column name="customerId"/>
        </key>
        <list-index column="attemptId" base="1"/>
        <composite-element class="DeliveryAttempt">
            ...
        </composite-element>
    </set>
</class>

8.5. 動態組件 (Dynamic components)

You can also map a property of type Map:

<dynamic-component name="userAttributes">
    <property name="foo" column="FOO" type="string"/>
    <property name="bar" column="BAR" type="integer"/>
    <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
</dynamic-component>

The semantics of a <dynamic-component> mapping are identical to <component>. The advantage of this kind of mapping is the ability to determine the actual properties of the bean at deployment time just by editing the mapping document. Runtime manipulation of the mapping document is also possible, using a DOM parser. You can also access, and change, Hibernate's configuration-time metamodel via the Configurationobject.

3.component的annotation的實例

仍然使用之前的Husband和Wife,其中Wife作為Husband的component,Wife不適用註解,在Husband中引用Wife,併在getWife上使用@Embedded

Wife

package com.baosight.model;


public class Wife {
    private String wifeId;
    private String WifeName;
    private String age;
    public String getWifeId() {
        return wifeId;
    }
    public void setWifeId(String id) {
        this.wifeId = id;
    }
    public String getWifeName() {
        return WifeName;
    }
    public void setWifeName(String name) {
        this.WifeName = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
}

Husband

package com.baosight.model;

import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Husband {
    private String id;
    private String name;
    private Wife wife;
    @Id
    @GeneratedValue//auto
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Embedded
    public Wife getWife() {
        return wife;
    }
    public void setWife(Wife wife) {
        this.wife = wife;
    }
}

 註意,在hibernate.cfg.xml中只需引用Husband

<mapping class="com.baosight.model.Husband"/>

JUnit測試類OrMappingTest.java

package com.baosight.model;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class OrMappingTest {
    private static SessionFactory sf = null;
    @BeforeClass
    public static void beforeClass(){
        // 讀取配置文件
        Configuration cfg = new AnnotationConfiguration();
        // 得到session工廠
        sf = cfg.configure().buildSessionFactory();
    }
    @Test
    public void testSchemaExport() {
        new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
    }
    @AfterClass
    public static void afterClass(){
        // 關閉session工廠
        sf.close();
    }
}

使用上類進行JUnit測試,結果為:

4.component的xml的實例

仍然使用之前的Student和StudentCard,其中StudentCard作為Student的component,StudentCard不需要xml配置文件,在Student中引用StudentCard,併在Student.hbm.xml使用

<component name="card">
<property name="cardId"></property>
<property name="num"></property>
</component>

StudentCard

package com.baosight.model;


public class StudentCard {
    private String cardId;
    private String num;
    public String getCardId() {
        return cardId;
    }
    public void setCardId(String id) {
        this.cardId = id;
    }
    public String getNum() {
        return num;
    }
    public void setNum(String num) {
        this.num = num;
    }
    
}

Student

package com.baosight.model;


public class Student {
    private String id;
    private String name;
    private int age;
    private StudentCard card;
//    private StudentPK pk;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
/*    public StudentPK getPk() {
        return pk;
    }
    public void setPk(StudentPK pk) {
        this.pk = pk;
    }*/
    public StudentCard getCard() {
        return card;
    }
    public void setCard(StudentCard card) {
        this.card = card;
    }
    
}

Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.baosight.model">
<class name="Student" dynamic-update="true">
<id name="id" >
<generator class="native"></generator>
</id>
<!-- <property name="name"></property> -->
<property name="age"></property>
<component name="card">
<property name="cardId"></property>
<property name="num"></property>
</component>
</class>
</hibernate-mapping>

註意,在hibernate.cfg.xml中只需引用Student.hbm.xml,StudentCard無對應的xml

<mapping resource="com/baosight/model/Student.hbm.xml"/>

仍然使用3中的JUnit測試,測試結果見3中。

以上即為hibernate的component的基本用法,需要在實際地使用中仔細體會。  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • 前幾天看了開源的XML文件解析器TinyXml,它是怎麼實現解析的沒怎麼看懂,於是決定自己實現一個,反正最近不忙。先命名為TXml。現在完成瞭解析和查詢功能,全部代碼加起來不到1000行,將會繼續完善它。源碼必共用 先簡單說一下我的思路: 1:讀取XML文件信息,並存入一個字元數組中; 2:遍曆數組 ...
  • 常見的狀態碼以及其含義 一些常見HTTP狀態碼為: 200 -- 伺服器成功返回網頁 400 -- 伺服器不理解請求的語法 404 -- 請求的網頁不存在 503 -- 服務不可用 常見HTTP狀態碼大全 1xx(臨時響應):表示臨時響應並需要請求者繼續執行操作的狀態代碼。 http狀態碼 100( ...
  • 一.為什麼要使用介面 假如有一個需求:要求實現防盜門的功能。門有"開"和"關"的功能,鎖有"上鎖"和"開鎖"的功能。 分析:首先防盜門是一個門,門有開門和關門的功能,還有一把鎖,鎖有開鎖和上鎖,按照面向對象的編程的思想,我們會將門和鎖都作為一個類而單獨存在,但是,不能讓防盜門繼承自門的同時又繼承自鎖 ...
  • static靜態,作為修飾符,最初是由c引入,一開始static表示退出一個塊後依然存在的局部變數。隨後,static表示不能被其他文件訪問的全局變數和函數。到了C++和java,static表示屬於類且不屬於類對象的變數和函數。 從具體用法來看,主要用到5個方面。 一、靜態域。 static修飾類 ...
  • 本地事務 事務類型 事務可以分為本地事務和分散式事務兩種類型。這兩種事務類型是根據訪問並更新的數據資源的多少來進行區分的。本地事務是在單個數據源上進行數據的訪問和更新,而分散式事務是跨越多個數據源來進行數據的訪問和更新。在這裡要說的事務是基於資料庫這種數據源的。 JDBC事務 在JAVA中,我們使用 ...
  • python 的PIL安裝是一件很蛋痛的事, 如果你要在python 中使用圖型程式那怕只是將個圖片從二進位流中存檔(例如使用Scrapy 爬網存圖),那麼都會使用到 PIL 這庫,而這個庫是出名的難安裝. 它的表現為,如果你使用 Scrapy 的ImagePipeline 它就會預設使用PIL,如 ...
  • 版權聲明:本文為博主原創文章,如需轉載請註明出處。 準備 編譯好的Hotspot虛擬機 "Java虛擬機(HOTSPOT)源代碼編譯步驟" : GDB基本操作: "Linux編程基礎——GDB(入門)" "Linux編程基礎——GDB(設置斷點)" 系統: Ubuntu 14.04 調試步驟 可調試 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...