Hibernate關聯關係
轉http://blog.csdn.net/wmingluo/archive/2006/09/05/1180972.aspx
在域模型鍾,類與類之間最普遍的關係就是關聯關係。例如,客戶(Customer)和訂單(Order)的關係,一個客戶能發出多個訂單,耳一個訂單隻能屬於一個客戶。從Order到Customer的關係是多對一關係,意味著每個Order對象都會引用一個Customer物件,下面就以Customer和Order之間的關係例子來介紹關聯關係。
一, 一對多的單向關聯關係
[@more@]
首先先建立Customer和Order類,程式碼如下:
Customer類:
package mypack;
import java.io.Serializable;
import org.apache.commons.lang.builder.ToStringBuilder;
public class Customer implements Serializable {
private Long id;
private String name;
public Customer(String name) {
this.name = name;
}
public Customer() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String toString() {
return new ToStringBuilder(this)
.append("id", getId())
.toString();
}
}
Order類:
package mypack;
import java.io.Serializable;
import org.apache.commons.lang.builder.ToStringBuilder;
public class Order implements Serializable {
private Long id;
private String orderNumber;
private mypack.Customer customer;
public Order(String orderNumber, mypack.Customer customer) {
this.orderNumber = orderNumber;
this.customer = customer;
}
public Order() {
}
public Order(mypack.Customer customer) {
this.customer = customer;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getOrderNumber() {
return this.orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
public mypack.Customer getCustomer() {
return this.customer;
}
public void setCustomer(mypack.Customer customer) {
this.customer = customer;
}
public String toString() {
return new ToStringBuilder(this)
.append("id", getId())
.toString();
}
}
Customer和Order類的配置檔案分別是Customer.hbm.xml和Order.hbm.xml
Customer.hbm.xml如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
">
<hibernate-mapping >
<class name="mypack.Customer" table="CUSTOMERS" >
<id name="id" type="long" column="ID">
<generator class="increment"/>
id>
<property name="name" type="string" >
<column name="NAME" length="15" />
property>
class>
</hibernate-mapping>
Order.hbm.xml如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
">
<hibernate-mapping >
<class name="mypack.Order" table="ORDERS">
<id name="id" type="long" column="ID">
<generator class="increment"/>
id>
<property name="orderNumber" type="string" >
<column name="ORDER_NUMBER" length="15" />
property>
<many-to-one
name="customer"
column="CUSTOMER_ID"
class="mypack.Customer"
not-null="true"
/>
class>
hibernate-mapping>
在Order.hbm.xml中<many-to-one>元素建立了Customer和ORDERS表的外來鍵CUSTOMER_ID之間
的對映。
它包括如下屬性。
● name:設定待對映的持久化類的屬性名,此處為Order類的customer屬性。
● column:設定和持久化類的屬性對應的表的外來鍵,此處為ORDERS表的外來鍵CUSTOMER_ID。
● class:設定持久化類的屬性的型別,此處設定customer屬性為Customer類。
● not-null:如果為ture,表示customer屬性不能為null,預設為false。
接下來我們持久化一個Customer物件以及和他關聯的Order物件:
(以下程式碼並非是完整程式碼,只是簡單把邏輯列出)
Configuration config = new Configuration();
config.addClass(Customer.class)
. addClass(Order.class);
sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = null;
tx = session.beginTransaction();
Customer customer=new Customer("Jack");
session.save(customer);
Order order1=new Order("Jack_Order001",customer);
Order order2=new Order("Jack_Order002",customer);
session.save(order1);
session.save(order2);
tx.commit();
當我們要持久化一個Customer物件以及和他關聯的Order物件的時候一定要先建立Customer對象並持久化它,否則當建立Order持久物件的時候會丟擲異常,如果把session.save(customer)
登出將會在session.save(order1)丟擲PropertyValueException異常。分析產生異常原因:在呼叫session.save(order1)方法之前,order1和customer物件都是臨時物件,臨時物件就是剛剛用new建立出來,但是還沒有持久會的物件,而Hibernate不會自動持久化order1關聯的customer物件,在資料庫中意味著僅僅向ORDERS表中插入了一條記錄,並且該記錄的CUSTOMER_ID欄位為null,違反了資料庫完整性約束,因為不允許ORDERS表的CUSTOMER_ID欄位為null。
從上面的例子可以看出當Hibernate持久化一個臨時物件時,在預設情況下,它不會自動持久化所關聯的其他臨時物件,所以會丟擲PropertyValueException異常。如果希望當Hibernate持久化Order物件時自動持久化所關聯的Customer物件,可以把<many-to-one>的cascade屬性設為“save-update”,cascade屬性預設為“none”:
<many-to-one
name="customer"
column="CUSTOMER_ID"
class="mypack.Customer"
cascade=“save-update”
not-null="true"
/>
這樣就能夠在Hibernate持久化Order物件時自動持久化所關聯的Customer物件了。
二, 一對多的雙向關聯關係
我們依然使用前面的Customer和Order的例子,由於是雙向關聯,Order類程式碼如上面一樣,由於Customer類中有Order的關聯物件,因此Customer類改為如下:
package mypack;
import java.io.Serializable;
import java.util.Set;
import org.apache.commons.lang.builder.ToStringBuilder;
public class Customer implements Serializable {
private Long id;
private String name;
private Set orders;
public Customer(String name, Set orders) {
this.name = name;
this.orders = orders;
}
public Customer() {
}
public Customer(Set orders) {
this.orders = orders;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Set getOrders() {
return this.orders;
}
public void setOrders(Set orders) {
this.orders = orders;
}
public String toString() {
return new ToStringBuilder(this)
.append("id", getId())
.toString();
}
}
如何在對映檔案中對映集合型別的order屬性呢?由於在CUSTOMERS表中沒有直接與order屬性對應的欄位,因此不能用<property>元素來對映order屬性,而是要使用<set>元素:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
">
<hibernate-mapping >
<class name="mypack.Customer" table="CUSTOMERS" >
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" >
<column name="NAME" length="15" />
</property>
<set
name="orders"
cascade="save-update"
>
<key column="CUSTOMER_ID" />
<one-to-many class="mypack.Order" />
</set>
</class>
</hibernate-mapping>
<set>元素還包含兩個子元素:<key>和<one-to-many>,<one-to-many>元素設定所關聯的持久化類,此處為Order類,<key>元素設定與所關聯的持久化對應的表的外來鍵,此處為ORDERS表的CUSTOMERS_ID欄位。
它包括如下屬性:
● <set>元素表明Customer類的orders屬性為java.util.Set集合型別。
● <one-to-many>表明orders集合中存放的是一組Order物件。
● <key>屬性表明ORDERS表透過外來鍵CUSTOMERS_ID參照CUSTOMERS表。
● cascade 屬性取值為"save-update",表明當儲存或更新Customer物件時,會級聯儲存或更新orders集合中的所有Order物件。
接下來我們持久化一個Customer物件以及和他關聯的Order物件:
Session session = sessionFactory.openSession();
Transaction tx = null;
tx = session.beginTransaction();
Customer customer=new Customer("Tom",new HashSet());
Order order=new Order();
order.setOrderNumber("Tom_Order001");
order.setCustomer(customer);
customer.getOrders().add(order);
session.save(customer);
tx.commit();
當<set>元素的cascade屬性為"save-update"時,Hibernate在持久化Customer物件時,會自動持久化關聯的Order物件。
如果是載入持久化物件,然後再建立關聯關係,那又該怎麼做呢?如下所示:
Session session = sessionFactory.openSession();
Transaction tx = null;
tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,new Long(2));
Order order=(Order)session.load(Order.class,new Long(2));
order.setCustomer(customer);
customer.getOrders().add(order);
tx.commit();
Hibernate會自動清理快取中的所有持久化物件,按照持久化物件狀態改變來同步更新資料庫,Hibernate在清理以上Customer物件和Order物件時執行了以下兩條SQL語句:
update ORDERS set ORDER_NUMBER='Jack_Order001',CUSTOMER_ID=2 where ID=2;
update ORDERS set CUSTOMER_ID=2 where ID=2;
儘管只是修改了ORDERS表的一條記錄,但是以上SQL語句表明Hibernate執行了兩次update操作這是因為HIbernate根據記憶體中持久化物件的狀態變化來決定需要執行的SQL語句,order.setCustomer(customer)執行的相應SQL語句為:
update ORDERS set ORDER_NUMBER='Jack_Order001',CUSTOMER_ID=2 where ID=2;
customer.getOrders().add(order)執行的相應SQL語句為:
update ORDERS set CUSTOMER_ID=2 where ID=2;
重複執行對於的SQL語句會影響應用程式的效能,那麼解決的辦法是把<set>元素的inverse屬性設定為true,預設為false:
<set
name="orders"
cascade="save-update"
inverse="ture"
>
<key column="CUSTOMER_ID" />
<one-to-many class="mypack.Order" />
set>
因此在對映一對多雙向關聯關係時,應該在"one"方把inverse屬性設為“ture”,這樣可以提高效能。
三,一對多雙向自身關聯關係
以食品為例,它代表商品類別,存在一對多雙向自身關聯關係。如下圖所示,水果類別屬於食品類別,同時它又包含兩個子類別:蘋果類別和桔子類別。
圖中每一種商品代表一個Category物件,這些物件形成了樹型資料結構。每個Category
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12058779/viewspace-1000307/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Hibernate 的關聯關係對映
- Hibernate 實體關聯關係對映—-總結薦
- hibernate 關係對映之 主鍵關聯一對一
- Hibernate級聯關係的說明和優化優化
- 表的關聯關係
- hibernate(六) cascade(級聯)和inverse關係詳解
- 關聯關係與依賴關係的區別
- mybatis關聯關係對映MyBatis
- python 類關聯關係Python
- 【原創】WEB元件的關聯關係Web元件
- hibernate 繼承對映關係( JOINED)繼承
- hibernate物件關係的翻譯稿物件
- 關於Hibernate多層1對多關係查詢
- 物件導向程式設計程式碼詳解(依賴關係,關聯關係,組合關係)物件程式設計
- 8 張圖掌握 Laravel 的 Eloquent 關聯關係Laravel
- 6.Hibernate多對多關係建立
- hibernate(三) 一對多對映關係
- Hibernate (開源物件關係對映框架)物件框架
- hibernate(五) hibernate一對一關係對映詳解
- 樹形或級聯關係
- 關於Hibernate一對多關聯儲存問題
- 兩個類的關係,應該如何關聯?
- hibernate中多對多關係的維護
- 物聯網與APP的關係?APP
- Laravel Eloquent 的關係模型聯動Laravel模型
- Mybatis 多表關聯查詢(1) one-to-one關係MyBatis
- CPA二十--關聯方關係的披露要求(轉載)
- hibernate(四) 雙向多對多對映關係
- hibernate 繼承對映關係( SINGLE_TABLE)繼承
- hibernate 繼承對映關係( TABLE_PER_CLASS)繼承
- Hibernate對映檔案一對多關係薦
- 設計模式存在哪些關聯關係,六種關係傻傻分不清--- UML圖示詳解設計模式
- JPA關係對映系列五:many-to-many 關聯表存在額外欄位關係對映
- hibernate annotation註解方式來處理對映關係
- Hibernate中有一對多關係,如何插入資料呢
- 在Java中,以下有關類的關聯關係描述錯誤的是()Java
- 海量文字中挖掘人物關聯關係核心技術介紹
- SAP Spartacus 的 TMS 和 Event Service 實現的關聯關係