組合關係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,具體以下:
使用方式與一對多多對一相同。