前言:在域对象(1.实体域对象2.过程域对象3.事件域对象)中,类与类之间最普遍的关系就是关联关系(还有1.依赖:类使用另一个类的方法或属性2.聚集:类聚集成整体3.一般化:类之间的继承),用它来描述一对一或多对一的数据关系
建立多对一的单向关联关系
类与类的多对一单向关联和关系数据库中的外键参照关系匹配.Order到Customer的多对一单向关联,在Order类中定义一个Customer类型的customer属性,而Customer无需定义用于存放Order对象的集合。注意这是单向关联(ORDER表中有一个外键CUSTOMER_ID引用CUSTOMER的ID),映射文件配置如:
在过程域中的相关方法说明如下:
1. savaCustomerAndOrder(){
tx=session.beginTransaction();
Customer customer=new Customer(“Tom”);
session.sava(customer);
//order与customer关联
Order order=new Order(“Tom_Order 001”,customer);
session.save(order);
tx.commit();
}
2. savaCustomerAndOrderWithCascade(){
tx=session.beginTransaction();
Customer customer=new Customer(“Tom”);
//session.sava(customer);不保存customer对象,保存order会出异常
因为外键引用不存在,
Order order=new Order(“Tom_Order001”,customer);
session.save(order);
tx.commit();
}
3. findOrdersByCustomer(Customer customer){
tx = session.beginTransaction();
List orders=(List)session.find("from Order as o where o.customer.id= "+customer.getId());
tx.commit();
return orders;
}
<many-to-one>元素的not-null属性
如上配置,把not-null去掉,意识着外键值可以为空.这样执行以上2的方法
savaCustomerAndOrderWithCascade()时会保存order成功,但是在Hibernate自动清理(flush,即同步更新数据库)时,会抛出异常(1.不先保存customer,customer就没有主键。)
Hibernate持久化一个对象时,不会自动持久化与其关联的对象.如果希望Hibernate持久化Order对象时自动持久化所关联的Customer对象.配置如下:
<many-to-one name=”customer” not-null=”true”column=”CUSTOMER_ID” class=”mypack.Customer” cascade= ”sava-update”/>
保存或更新当前对象时会级联保存或更新与它关联的对象
映射一对多双向关联关系
当类与类建立关联,可以方便从一个对象导航到另一个或一组对象,如Customer customer=order.getCustomer();从而获取如两表连接的信息,而又不用去数据库查询,速度快.如何获得与某个Customer关联的所有Order对象?这需要在Customer类中增加一个集合类型的orders属性如:private Set orders=new HashSet();有了这个属性,对于给指定的客户查询其所有订单只要调用customer.getOrders()方法就可以了.注意hbm2java只会生成:private Set orders;=new HashSet()是手工添加的,以提高程序健壮性,避免程序访问null的orders时发生异常.映射文件配置如下:
<set name=”orders” cascade=”save-update” >//order属性为java.uitl.Set集合类型,cascade表明当保存或更新Customer对象时,会级联保存或更新orders集合中的Orders对象<key column=”CUSTOMER_ID”/>//ORDER表连接customer表的外键
<one-to-many class=”mypack.Order”/>//一对多关系
</set>. //CUSTOMER表中没有与ORDER对应的字段
一些方法说明如下:
1. savaCustomerAndOrderWithCascade(){
tx=session.beginTransaction();
Customer customer=new Customer(“Tom” ,new HashSet());
Order order=new Order();
order.setCustomer(customer);
customer.getOrders().add(order);
//保存customer时级联保存与orders属性关联的order对象
session.save(customer);
tx.commit();
}
元素的inverse(反转)属性
saveCustomerAndOrderWithInverse()用于演示inverse属性的用户,它调用以下两个方法.
1. saveCustomerAndOrderSeparately(){
tx=session.beginTransaction();
Customer customer=new Customer();
customer.setName=”Jack”;
Order order=new Order();
order.setOrderNumber(“Jack_Order001”);
session.save(customer);
//order没有设置与customer关联,保存出异常,因为它的customer属性在映射时指定不为空
session.save(order);
}
2. associateCustomerAndOrder(){
tx=session.beginTransaction();
//加载以上代码持久化的对象
Customer customer=(Customer)session.load(Customer.class, new Long(2));
Order order=( Order)session.load(Order.class, new Long(2));
//建立Customer和Order的关联关系
order.setCustomer(customer);
//order发生变化,执行uddate ORDER SET ….where ID=2;
customer.getOrders().add(order);
// customer发生变化,执行uddate ORDER SET ….where ID=2;
tx.commit();
}
以上执行两次SQL语句结果都是一样,影响了JAVA应用性能,解决方法是把<set>元素的inverse属性设为true;如:
<set name=”orders” cascade=”save-update” inverse=”true” >//只按照ORDER级联更新,CUSTOMER变化不会级联到ORDER
<key column=”CUSTOMER_ID”/>
<one-to-many class=”mypack.Order”/>
</set>
这样Customer和Order双向关联中,Hibernate探测到持久化对象Customer和Order的状态发生变化时,仅按照Order对象状态的变化来同步更新数据库.为了程序健壮,在建立两个对象的双向关联时,应同时修改两端对象的相应属性,如:
customer.getOrders().add(order);
order.setCustomer(customer);
解除关联时:
customer.getOrders().remove(order);
order.setCustomer(null);
如果希望Hibernate删除Customer对象时,自动删除和Customer关联的Order对象,可以把cascade属性设为”delete”,Customer的映射文件配置如下:
<set name=”orders” cascade=”delete” inverse=”true”>
<key column=”CUSTOMER_ID”/>
<one-to-many class=”mypack.Order”/>
</set>
删除一个持久化对象,就是从数据库中删除相关记录,内存中的对象依然存在,不过由持久化状态变为临时状态了
tx=session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class, new Long(2));
Order order=(Order)customer.getOrders().iterator().next();
//解除Customer对象和Order对象的关联关系
customer.getOrders().remove(order)
order.setCustomer(null);
//执行update ORDERS set CUSTOMER_ID=null wher ID=2;
tx.commit();
如果希望Hibernate自动删除不再和Customer对象关联的Order对象,可以把cascade设为”all-ete-orphan(孤立)”,映射文件配置为:
<set name=”orders” cascade=”all-delete-orphan” inverse=”true”>
<key column=”CUSTOMER_ID”/>
<one-to-many class=”mypack.Order”/>
</set>
当Customer.hbm.xml的<set>元素的cascade属性取为”all-delete-orphan”.当保存或更新Customer对象时,级联保存或更新有关的Order对象,当删除Customer对象时,级联删除有关的Order对象.
这种类的特点是有一个属性是他本身类型(外键引用自身表的ID),还有一个集合属性用来装载自身类(主键被自身表的外键引用),它的映射文件如:
<set
name="childCategories"
cascade="save-update"//对save或update起作用
inverse="true"//对非增删改查引起的对象状态变化起作用?2007-3-9
>
<key column="CATEGORY_ID" />
<one-to-many class="mypack.Category" />//Category: 种类
</set>
<many-to-one
name="parentCategory"
column="CATEGORY_ID"
class="mypack.Category"
/>
自解:如人这个类,它有一个属性人,用来装载它的父亲信息,还有一个集合用来装载它的儿子信息
.这里父我子都使用同一个类(主键与外键的关系,以后我都说是父子关系),这样一个对象就可以装载
多表关联的信息了
一些相关方法说明如下:
saveCategoryWithCascade(){
tx=session.geginTransaction();
Category foodCategory=new Category(“food”,null,new HashSet());//食品种类
Category fruitCategory=new Category(“fruit”,null,new HashSet());//水果种类
foodCategory.getChildCategories().add(fruitCategory);//建立关联
fruitCategory.setParentCategory(foodCategory); //建立关联
session.save(foodCategory);//会级联保存
tx.commit();
}
改进持久化类
通过hbm2java工具自动生成的持久化类,可以根据实际需要加入适当的业务逻辑或实用方法(这个方
法供应用程序调用,Hibernate只调用属性的getXXX和setXXX)