學習hibernate(五) -- hibernate映射關係

組合關係java

    在開發時,有一種狀況,有一張數據表的數據來自於多個對象。好比,一個computer(電腦)表,其中有電腦的基本信息、CPU信息、顯卡信息、主板信息和內存信息等等,對應的實體對象則是電腦對象、CPU對象、顯卡對象和內存對象。這種狀況下可使用組合關係映射。sql

    以電腦與CPU爲例,Computer類中包含了一個Cpu類,在*.hbm.xml文件中,使用component來進行組合關係映射。數據庫

    看一下這兩個實體類的代碼和映射文件:session

package cn.net.bysoft.model;

public class Computer {
//getter and setter

    private int id;
    private String name;
    private Cpu cpu;
}
package cn.net.bysoft.model;

public class Cpu {

    //getter and setter

    private String name;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.net.bysoft.model">
    <class name="Computer" table="computer">
        <id name="id" type="integer" column="ID">
            <!-- 指定主鍵的生成方式,native是使用數據庫本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 使用組合關係映射,CPU的Name信息存放在Cpu_Name字段中。 -->
        <component name="cpu" class="Cpu">
            <property name="name" type="string" column="CPU_NAME"></property>
        </component>
    </class>
</hibernate-mapping>

    生成的數據表並測試save方法:app

@Test
    public void testComponent() throws IOException {
        //    save一個組合關係對象。
        Computer computer = new Computer();
        computer.setName("pc");
        Cpu cpu = new Cpu();
        cpu.setName("Inter");
        computer.setCpu(cpu);
        session.save(computer);
    }

一對多與多對一測試

    一對多與多對一關聯,通常用於一個對象包含另外一個對象的集合,被包含的對象中存在包含對象的實體,好比一個customer能夠有多比訂單(order)。在數據表中,order表有customer表的外鍵。spa

    在*.hbm中,一的一端使用set標籤設置多的一端的集合,在set中加入key與one-to-many。.net

    多的一端使用<one-to-may>屬性配置一對多。hibernate

    看一下實體類代碼和配置文件:code

package cn.net.bysoft.model1;

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

public class Customer {
    getter/setter屬性
    
    private int Id;
    private String name;
    //    一對用戶能夠有多個訂單。
    private Set<Order> orders = new HashSet<Order>();
}
package cn.net.bysoft.model1;

public class Order {
    getter/setter屬性
    
    private int id;
    private String name;
    //    每一個訂單都屬於一個用戶。
    private Customer customer;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Customer" table="CUSTOMERS">
        <id name="id" type="integer" column="ID">
            <!-- 指定主鍵的生成方式,native是使用數據庫本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 一對多 -->
        <set name="orders" table="ORDERS">
            <key column="CUSTOMER_ID"></key>
            <one-to-many class="cn.net.bysoft.model1.Order"/>
        </set>
    </class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Order" table="ORDERS">
        <id name="id" type="integer" column="ID">
            <!-- 指定主鍵的生成方式,native是使用數據庫本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 多對一 -->
        <many-to-one name="customer" class="cn.net.bysoft.model1.Customer" column="CUSTOMER_ID">
        </many-to-one>
    </class>
</hibernate-mapping>

    新增和刪除的時候有一些須要注意的地方,看一段save代碼:

    @Test
    public void testOneToManySave() {
        Customer customer = new Customer();
        customer.setName("Kobe");

        Order order1 = new Order();
        order1.setName("buy book");
        Order order2 = new Order();
        order2.setName("buy ball");

        customer.getOrders().add(order1);
        customer.getOrders().add(order2);

        order1.setCustomer(customer);
        order2.setCustomer(customer);

        session.save(customer);
        session.save(order1);
        session.save(order2);

        /**
         * output: Hibernate: 
         * insert into CUSTOMERS (NAME) values (?) 
         * insert into ORDERS (NAME, CUSTOMER_ID) values (?, ?) 
         * insert into ORDERS (NAME, CUSTOMER_ID) values (?, ?)
         * */
    }

    先save一的一端,在save多的一端,會打印三條sql語句,是正常的。若是先保存多的一端在保存一的一端,會輸出七條sql語句,其中有4條是update語句,由於先保存多的一端,此時並無一的一端的主鍵,等到保存好一的一端後,在回頭由兩端都進行update。

        session.save(order1);
        session.save(order2);
        session.save(customer);

        /**
         * output: 
         * Hibernate: insert into ORDERS (NAME, CUSTOMER_ID) values (?,?) 
         * Hibernate: insert into ORDERS (NAME, CUSTOMER_ID) values (?, ?)
         * Hibernate: insert into CUSTOMERS (NAME) values (?) 
         * Hibernate: update ORDERS set NAME=?, CUSTOMER_ID=? where ID=? 
         * Hibernate: update ORDERS set NAME=?, CUSTOMER_ID=? where ID=? 
         * Hibernate: update ORDERS set CUSTOMER_ID=? where ID=? 
         * Hibernate: update ORDERS set CUSTOMER_ID=? where ID=?
         * */

    正常來講,不須要兩端都進行update維護,要解決該問題須要在一端加入inverse屬性,建議由多的一端去控制,因此在Customer.hbm.xml中的set節點中加入:

<set name="orders" table="ORDERS" inverse="true">

    在進行保存時,update語句減小了,只由多的一端維護關係:

    再來講說delete。刪除時在不設置級聯的狀況下,不能刪除一的一端,由於這一端的主鍵被關鍵關聯着:

    @Test
    public void testOneToManyDelete() {
        Customer customer = (Customer) session.get(Customer.class, 1);
        session.delete(customer);
        /**
         * output: 
         * INFO: HHH000010: On release of batch it still contained JDBC statements
         * */
    }

    使用級聯關係的屬性是cascade,該屬性有三個值,分別是:

  • delete:刪除一的一端,會連帶着刪除多的一端;

  • delete-orphan:一的一端使用多的一端的集合的clear屬性能夠刪除多的一端;

  • save-update:值保存一的一端,多的一端會自動保存;

    在設置好級聯關係後,可直接刪除一的一端:

<set name="orders" table="ORDERS" inverse="true" cascade="delete">

    在項目中建議使用手動控制關聯關係。

一對一

    有兩種狀況均爲一對一關聯關係,一個部門有一個部門經理。可使用某一個字段作外鍵,也可使用主鍵作外鍵。先來看看主外鍵狀況作一對一。

    在Manager對象的配置文件中加入<one-to-one>節點,而Dept對象中加入<many-to-one>節點,對該節點加入unique屬性進行惟一約束,下面是實體類與配置文件內容:

package cn.net.bysoft.model1;

public class Dept {
    //getter/setter

    private int id;
    private String name;
    private Manager manager;
}
package cn.net.bysoft.model1;

public class Manager {
    //getter/setter
    
    private int id;
    private String name;
    private Dept dept;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Dept" table="DEPT">
        <id name="id" type="integer" column="ID">
            <!-- 指定主鍵的生成方式,native是使用數據庫本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 多對一 -->
        <many-to-one name="manager" class="cn.net.bysoft.model1.Manager"
            column="MANAGER_ID" unique="true"></many-to-one>
    </class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Manager" table="MANAGER">
        <id name="id" type="integer" column="ID">
            <!-- 指定主鍵的生成方式,native是使用數據庫本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <!-- 一對一 -->
        <one-to-one name="dept" class="cn.net.bysoft.model1.Dept" property-ref="manager"></one-to-one>
    </class>
</hibernate-mapping>

    接下來是主鍵與主鍵作一對一關係,實體類無需改變,只須要修改dept的配置文件,將id節點的class修改爲foreign模式,將many-to-one修改爲one-to-one,添加constrained屬性等於true,具體以下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.net.bysoft.model1.Dept" table="DEPT">
        <id name="id" type="integer" column="ID">
            <!-- 指定主鍵的生成方式,native是使用數據庫本地的方式 -->
            <generator class="foreign">
                <param name="property">manager</param>
            </generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <one-to-one name="manager" class="cn.net.bysoft.model1.Manager" constrained="true">
        </one-to-one>
    </class>
</hibernate-mapping>

    增刪改查方法的調用與一對多多對一同樣。

多對多

    用數據表描述多對多,須要有三張表,A表,B表,A-R-B表。

    用對象描述多對多,A對象中有B對象的集合,B對象中也有A對象的集合。

    舉個例子,如今有訂單類與商品類,一個訂單中能夠有多個商品,而一個商品也能夠屬於多個訂單。看一下實體類的代碼:

package cn.net.bysoft.model1;

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

public class Orders {

    //getter and setter

    private int id;
    private String name;
    private Set<Products> products = new HashSet<Products>();
}
package cn.net.bysoft.model1;

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

public class Products {
    //getter and setter

    private int id;
    private String name;
    private Set<Orders> orders = new HashSet<Orders>();
}

    兩個對象的配置文件也很像,每一個配置文件中都有set節點,可是在多對多中,必須有一個set的inverse=true,具體以下:

    使用方式與一對多多對一相同。

相關文章
相關標籤/搜索