天天看點

Hibernate學習之關聯關系映射介紹單向關聯基于連接配接表的單向關聯雙向關聯基于連接配接表的雙向關聯

介紹

從單向關系映射開始,然後考慮雙向關系映射,逐漸講解典型的案例。

在單向關聯的例子中,将用 Student類和 Classes類。

在雙向關聯的例子中,将用 Person類和 Event類。

單向關聯

多對一

單向 many-to-one 關聯是最常見的單向關聯關系。

Student.java

package com.dfdc.hibernate.domain;

import java.io.Serializable;

public class Student implements Serializable{

    private static final long serialVersionUID = 1L;

    private Long sid;
    private String sname;
    //維護多對一
    private Classes clazz;

    public Classes getClazz() {
        return clazz;
    }
    public void setClazz(Classes clazz) {
        this.clazz = clazz;
    }

    public Long getSid() {
        return sid;
    }
    public void setSid(Long sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }

}
           

Classes.java

import java.io.Serializable;
import java.util.Set;

public class Classes implements Serializable{

    private static final long serialVersionUID = 1L;

    private Long cid;
    private String cname;       

    public Long getCid() {
        return cid;
    }

    public void setCid(Long cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }   

}
           

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>
    <class name="com.dfdc.hibernate.domain.Student" table="STUDENT">
        <id name="sid" type="java.lang.Long">
            <column name="SID" />
            <generator class="native" />
        </id>
        <property name="sname" type="java.lang.String">
            <column name="SNAME" />
        </property>

        <!-- 多對一,無關聯表 -->        
        <many-to-one name="clazz" column="CID" not-null="true"/>
    </class>
</hibernate-mapping>
           
以下為了代碼簡潔将省略DTD部分。

Classes.hbm.xml内容

<hibernate-mapping>
<class name="com.dfdc.hibernate.domain.Classes" table="CLASSES">
    <id name="cid" type="java.lang.Long">
        <column name="CID" />
        <generator class="native" />
    </id>
    <property name="cname" type="java.lang.String">
        <column name="CNAME" />
    </property>               
</class>
</hibernate-mapping>
           

一對一

基于外鍵關聯

基于外鍵關聯的單向一對一關聯和單向多對一關聯幾乎是一樣的。唯一的不同就是單向一對一關聯中的外鍵字段具有唯一性限制。

在上面Student.hbm.xml内容的節點增加unique=”true”

基于主鍵關聯

基于主鍵關聯的單向一對一關聯通常使用一個特定的 id 生成器。

注釋掉student類的clazz屬性,并在classes類中增加Student類型的stu屬性,即Classes類持有Student的引用。

Student.hbm.xml内容

<id name="sid" type="java.lang.Long">
    <column name="SID" />
    <generator class="native" />
</id>
<property name="sname" type="java.lang.String">
    <column name="SNAME" />
</property>
           

**Classes.hbm.xml内容**class節點内容改成如下:

<!--  基于主鍵的單向一對一 -->
<id name="cid" type="java.lang.Long">
    <column name="SID" />
    <generator class="foreign">
        <!-- property隻關聯對象 --> 
        <param name="property">stu</param>
    </generator>
</id>
<property name="cname" type="java.lang.String">
    <column name="CNAME" />
</property>
   <!-- constrained,通過一個外鍵引用對主鍵進行限制。-->
<one-to-one name="stu" constrained="true"/> 
           

一對多

基于外鍵關聯

基于外鍵關聯的單向一對多關聯是一種很少見的情況,我們不推薦使用它。

我們認為對于這種關聯關系最好使用連接配接表(關聯表)。

基于連接配接表的單向關聯

一對多(one-to-many)

基于連接配接表的單向一對多關聯應該優先被采用。

注意,通過指定unique=”true”,我們可以把多樣性從多對多改變為一對多。

student映射檔案内容:

<id name="sid" type="java.lang.Long">
<column name="SID" />
<generator class="native" />
</id>
<property name="sname" type="java.lang.String">
<column name="SNAME" />
</property>
           

classes映射檔案内容:

<id name="cid" type="java.lang.Long">
<column name="CID" />
<generator class="native"/> 
</id>
<property name="cname" type="java.lang.String">
<column name="CNAME" />
</property>
<!-- 基于連接配接表的多對多
    指定unique="true"轉換為兩個一對多 -->
<set name="students" table="CLASSES_STUDENT">
    <key column="CID"></key>
    <many-to-many column="SID" unique="true" class="com.dfdc.hibernate.domain.Student"></many-to-many>
</set>
           

注釋掉student類的clazz屬性,并在classes類中設定Set集合,屬性為students。

多對一(many-to-one)

基于連接配接表的單向多對一關聯在關聯關系可選的情況下應用也很普遍。

student映射檔案内容:

<id name="sid" type="java.lang.Long">
    <column name="SID" />
    <generator class="native" />
</id>
<property name="sname" type="java.lang.String">
    <column name="SNAME" />
</property>

<!-- 基于連接配接表的單向多對一
    table:被連接配接表的名稱。
    optional(可選 — 預設是 false):如果為true,Hibernate 
        隻會在此連接配接定義的屬性非空時插入一行資料,并且總是使用一個外連接配接來得到這些屬性。        
 -->
<join table="CLASSES_STUDENT" optional="true" >
    <key column="SID" unique="true"/>
    <many-to-one name="clazz" column="CID" not-null="true" unique="true"/>
</join>
           

classes映射檔案内容:

<id name="cid" type="java.lang.Long">
    <column name="CID" />
    <generator class="native"/> 
</id>
<property name="cname" type="java.lang.String">
    <column name="CNAME" />
</property>
           

以上的student類和classes類不變。

一對一(One-to-one)

基于連接配接表的單向一對一關聯也是可行的,但非常少見,就不舉例了。

多對多(many-to-many)

最後,這裡是一個單向多對多關聯的例子。

student映射檔案内容:

<id name="sid" type="java.lang.Long">
    <column name="SID" />
    <generator class="native" />
</id>
<property name="sname" type="java.lang.String">
    <column name="SNAME" />
</property>
 <!-- 基于連接配接表的單向多對多 -->
<set name="clazzSet" table="CLASSES_STUDENT">
    <key column="SID"/>
    <many-to-many column="CID" class="com.dfdc.hibernate.domain.Classes"/>
</set>
           

classes映射檔案内容:

<id name="cid" type="java.lang.Long">
    <column name="CID" />
    <generator class="native"/> 
</id> 
<property name="cname" type="java.lang.String">
    <column name="CNAME" />
</property>
           

把上面的student類的clazz屬性類型改成Set即可。

雙向關聯

從雙向關系映射開始,逐漸講解典型的案例。

在雙向關聯的例子中,将用 Event 和 Person。

Event.java

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

public class Event {

    private Long id;

    private Date date;

    private Set<Person> personSet = new HashSet<Person>();

    public Set<Person> getPersonSet() {
        return personSet;
    }

    public void setPersonSet(Set<Person> personSet) {
        this.personSet = personSet;
    }

    public Event() {}

        public Long getId() {
        return id;
    }

    //隻有hibernate能操作辨別符
    private void setId(Long id) {
        this.id = id;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

}
           

Person.java

import java.util.HashSet;
import java.util.Set;

public class Person {
    private Long id;
    private int age;

    public Person() {}                         

    public Long getId() {
        return id;
    }

    private void setId(Long id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    } 

}
           

一對多(one to many)/多對一(many to one)

雙向多對一關聯,是最常見的關聯關系。

person映射檔案内容:

<id name="id">
    <column name="PERSON_ID"/>
    <generator class="native"></generator>
</id>

<property name="age"/>
<!-- 雙向多對一/一對多 -->

<many-to-one name="events" column="EVENT_ID" class="com.dfdc.hibernate.domain.Event" not-null="true"/>
           

event映射檔案内容:

<id name="id">
    <column name="EVENT_ID" />
    <generator class="increment" />
</id> 
<property name="date" type="timestamp">
    <column name="DATE" />
</property>
<!-- 雙向一對多/多對一 -->
<set name="persons" inverse="true">
    <key column="EVENT_ID"/>
    <one-to-many class="com.dfdc.hibernate.domain.Person"/>
</set>        
           

在上面的person類添加Event類型的events屬性。

一對一(One-to-one)

基于外鍵關聯

基于外鍵關聯的雙向一對一關聯也很常見。

person映射檔案内容:

<id name="id">
    <column name="PERSON_ID"/>
    <generator class="native"></generator>
</id>

<property name="age"/>
<!-- 基于外鍵關聯雙向一對一
    unique,作為 property-ref 引用的目标。這使關聯同時具有一對一的效果。
 -->
<many-to-one name="events" column="EVENT_ID" unique="true" not-null="true"/>
           

event映射檔案内容:

<id name="id">
    <column name="EVENT_ID" />
    <generator class="native" />
</id> 
<property name="date" type="timestamp">
    <column name="DATE" />
</property>
 <!-- 基于外鍵關聯雙向一對一
    property-ref,被關聯到此外鍵的類中的對應屬性的名字。如果沒有指定,被關聯類的主鍵将被使用。
 -->
 <one-to-one name="persons" property-ref="events"/>
           

注釋掉Event類的set類型的屬性,并添加Person類型的屬性persons。

在Person類添加Event類型的屬性events。

基于主鍵關聯

person映射檔案内容:

<!-- 1.基于主鍵關聯雙向一對一 -->
    <id name="id">
        <column name="EVENT_ID"/>
        <!--
        foreign,擷取相關聯的對象的辨別符。它通常和 <one-to-one> 聯合起來使用。
        -->
        <generator class="foreign">
            <!--property,相關聯的對象 -->
            <param name="property">events</param>
        </generator>
    </id>

    <property name="age"/>
    <!--constrained="true",開啟目前類與關聯類之間的外鍵限制
            将影響級聯操作順序。
     -->
    <one-to-one name="events" class="com.dfdc.hibernate.domain.Event" constrained="true"/>
           

event映射檔案内容:

<id name="id">
    <column name="EVENT_ID" />
    <generator class="native" />
</id> 
<property name="date" type="timestamp">
    <column name="DATE" />
</property>
<!-- 1.基于主鍵關聯雙向一對一 -->
<one-to-one name="persons" class="com.dfdc.hibernate.domain.Person"/>
           

在上面的person類添加Event類型的events屬性。

在上面的event類添加Person類型的persons屬性,并注釋Set類型的persons屬性。

主鍵關聯不需要額外的表字段,兩個對象通過主鍵一對一關聯,必須确認它們被賦予同樣的辨別值。

基于連接配接表的雙向關聯

一對多(one to many)/多對一(many to one)

下面是一個基于連接配接表的雙向一對多關聯的例子。

person映射檔案内容:

<id name="id">
        <column name="PENSON_ID"/>
        <generator class="native"></generator>
    </id>

    <property name="age"/>
    <!-- 4. 基于連接配接表關聯雙向多對一/一對多 -->
    <set name="eventSet" table="PERSONEVENT">
        <key column="PERSON_ID"/>
        <many-to-many column="EVENT_ID" unique="true" class="com.dfdc.hibernate.domain.Event"/>
    </set>
           

event映射檔案内容:

<id name="id">
    <column name="EVENT_ID" />
    <generator class="native" />
</id> 
<property name="date" type="timestamp">
    <column name="DATE" />
</property>
<!-- 4. 基于連接配接表關聯雙向多對一/一對多 -->
<join table="PERSONEVENT" inverse="true" optional="true">
    <key column="EVETN_ID"/>
    <many-to-one name="persons" column="PERSON_ID" not-null="true"/>
</join>
           

在上面的Person類(代表一)中定義Set類型的eventSet屬性。

在event類(代表多)中注釋掉Set類型的persons屬性,并添加Person類型的persons屬性,即持有Person類的引用。

一對一(one to one)

基于連接配接表的雙向一對一關聯也是可行的,但極為罕見。這裡就不闡述了。

多對多(many-to-many)

下面是一個雙向多對多關聯的例子

person映射檔案内容:

<id name="id">
    <column name="PENSON_ID"/>
    <generator class="native"></generator>
</id>

<property name="age"/>
<set name="eventSet" table="person_event">
    <key column="PERSON_ID"></key>
    <many-to-many class="com.dfdc.hibernate.domain.Event" column="EVENT_ID"></many-to-many>
</set>
           

event映射檔案内容:

<id name="id">
    <column name="EVENT_ID" />
    <generator class="native" />
</id> 
<property name="date" type="timestamp">
    <column name="DATE" />
</property>
<set name="personSet" table="person_event" inverse="true">
    <key column="EVENT_ID"/>
    <many-to-many column="PERSON_ID" class="com.dfdc.hibernate.domain.Person"/>
</set>
           

在上面的Person類中定義Set類型的eventSet屬性。

以上。。。