转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"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<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/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12058779/viewspace-1000307/