欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

精通Hibernate:映射一对多关联关系(1)(2)

来源: javaer 分享于  点击 38955 次 点评:103

二、映射一对多双向关联关系

类类之间建立了联系,就可以很方便地从一个对象导航到另一个或者另一组与它相关联的对象。正如上例中,对于给定的Order对象,如果想获得与之关联的Customer对象,可以直接如下调用:

  1. Customer customer=order.getCustomer(); 

那么对于给定的Customer对象,如何一次获得所有与之关联的Order对象呢?由于上例中Customer对象没有和Order对象关联,我们也可以通过Hibernate API去查询数据库:

  1. List orders=session.createQuery("from Order as o where o.customer.id="+customer.getId()).list(); 

显然这样做的效率会很低,而且复杂的关联关系也会给编程带来影响。我们可以为Customer类和Order类简历一对多的双向关联。

第一部分我们已经建立了Order类和Customer类的多对一关联,现在我们再增加Customer到Order类的一对多关联。

Customer.java文件:

  1. package mypack;  
  2. import java.util.HashSet;  
  3.  
  4. import java.util.Set;  
  5. //Hibernate要求在持久化类中定义集合类属性时,必须要把属性声明为接口类型。  
  6.  
  7. public class Customer  implements java.io.Serializable {  
  8.      private long id;  
  9.      private String name;  
  10.      private Set orders = new HashSet();//初始化为集合实现类,这样做可以提高程序的健壮性,同时避免了应用程序访问取词为null的orders集合的方法而抛出NullPointerException。  
  11.     public Customer() {  
  12.     }  
  13.  
  14.     public Customer(String name, Set orders) {  
  15.        this.name = name;  
  16.        this.orders = orders;  
  17.     }  
  18.    //省略了id,name的get和set访问方法  
  19.     public Set getOrders() {  
  20.         return this.orders;  
  21.     }  
  22.       
  23.     public void setOrders(Set orders) {  
  24.         this.orders = orders;  
  25.     }  

接下来就是映射文件的配置Customer.hbm.xml:

  1. <class name="mypack.Customer" table="CUSTOMERS" >  
  2.   <id name="id" type="long" column="ID">  
  3.     <generator class="increment"/>  
  4.   </id>  
  5.  
  6.   <property name="name" type="string" >  
  7.       <column name="NAME" length="15" />  
  8.   </property>  
  9.   <set   
  10.       name="orders" 
  11.       cascade="save-update"   
  12.         
  13.         
  14.       <key column="CUSTOMER_ID" />//表示ORDERS表通过外键CUSTOMER_ID参照CUSTOMERS表  
  15.       <one-to-many class="mypack.Order" />  
  16.    </set>     
  17.  
  18. </class

使用方法のBussiness.java演示分函数介绍:

1)saveCustomerAndOrderWithCascade()方法:当映射文件中<set>的属性为“save-update”时,Hibernate在持久化Customer对象时也会自动持久化其所关联的Order对象

  1.   public void saveCustomerAndOrderWithCascade(){  
  2.     Session session = sessionFactory.openSession();  
  3.     Transaction tx = null;  
  4.     try {  
  5.       tx = session.beginTransaction();  
  6. /*创建一个customer对象和order对象*/ 
  7.       Customer customer=new Customer("Tom",new HashSet());  
  8.       Order order=new Order();  
  9.       order.setOrderNumber("Tom_Order001");  
  10. /*建立Customer与Order的一对多双向关联关系*/ 
  11.       order.setCustomer(customer);  
  12.       customer.getOrders().add(order);  
  13. /*保存Customer对象*/ 
  14.       session.save(customer);  
  15. /* 当映射文件中<set>的属性为“save-update”时,Hibernate在持久化Customer对象时也会自动持久化其所关联的Order对象  
  16.  insert into CUSTOMERS(ID,NAME) values(1,"Tom");  
  17.  insert into ORDERS(ID,ORDER_NUMBER,CUSTOMER_ID) values(1,"Tom_Order001",1)*/ 
  18.       tx.commit();  
  19.       idOfTom=customer.getId();  
  20.       idOfTomOrder=order.getId();    
  21.                     
  22.     }catch (RuntimeException e) {  
  23.       if (tx != null) {  
  24.         tx.rollback();  
  25.       }  
  26.       e.printStackTrace();  
  27.     } finally {  
  28.       session.close();  
  29.     }  
  30.   } 

当映射文件中<set>的属性为“save-update”时,Hibernate在持久化Customer对象时也会自动持久化其所关联的Order对象

  1. insert into CUSTOMERS(ID,NAME) values(1,"Tom");  
  2. insert into ORDERS(ID,ORDER_NUMBER,CUSTOMER_ID) values(1,"Tom_Order001",1

2)printOrdersOfCustomer(Long customerId)方法:打印与指定customerId关联的所有Order对象

  1. public void printOrdersOfCustomer(Long customerId){  
  2.   Session session = sessionFactory.openSession();  
  3.   Transaction tx = null;  
  4.   try {  
  5.     tx = session.beginTransaction();  
  6.     Customer customer=(Customer)session.get(Customer.class,customerId);  
  7.     printOrders(customer.getOrders());//使用getOrders获取一个order对象set  
  8.     tx.commit();  
  9.   }catch (RuntimeException e) {  
  10.     if (tx != null) {  
  11.        tx.rollback();  
  12.     }  
  13.     throw e;  
  14.   } finally {  
  15.      session.close();  
  16.   }  

其调用的函数printOrders(Set orders)

  1. public void printOrders(Set orders){  
  2.      for (Iterator it = orders.iterator(); it.hasNext();) {  
  3.         Order order=(Order)it.next();  
  4.         System.out.println("OrderNumber of "+order.getCustomer().getName()+ " :"+order.getOrderNumber());  
  5.      }  
  6.  } 

3)saveCustomerAndOrderWithInverse()方法:演示映射文件<set>属性为inverse

  1. public void saveCustomerAndOrderWithInverse(){  
  2.       saveCustomerAndOrderSeparately();  
  3.       associateCustomerAndOrder();  
  4.    } 

调用的函数saveCustomerAndOrderSeparately():即是分别存储,与saveCustomerAndOrderWithCascade()方法恰好相反。

  1. Customer customer=new Customer();  
  2. customer.setName("Jack");  
  3. Order order=new Order();  
  4. order.setOrderNumber("Jack_Order001");  
  5. session.save(customer);  
  6. session.save(order);&nbsp;  
  7. tx.commit();  
  8. idOfJack=customer.getId();  
  9. idOfJackOrder=order.getId(); 

为了使上述代码正常执行,需要确保Order.hbm.xml文件的<many-to-one>元素的not null取默认值false,否则会出现异常;Hibernate会执行如下

  1. insert into CUSTOMERS(ID,NAME) values(2,"Jack");  
  2. insert into ORDERS(ID,ORDER_NUMBER,CUSTOMER_ID) values(2,"Jack_Order001",null); 

调用的函数associateCustomerAndOrder():该方法加载由saveCustomerAndOrderSeparately()方法持久化Customer和Order对象,然后建立两者之间的一对多的关系

  1. public void associateCustomerAndOrder(){  
  2.    Session session = sessionFactory.openSession();  
  3.    Transaction tx = null;  
  4.    try {  
  5.      tx = session.beginTransaction();  
  6.      /*加载持久化对象Customer、Order*/ 
  7.      Customer customer=(Customer)session.load(Customer.class,idOfJack);  
  8.      Order order=(Order)session.load(Order.class,idOfJackOrder);  
  9.      /*建立Customer和Order的关联关系*/ 
  10.      order.setCustomer(customer);  
  11.      customer.getOrders().add(order);  
  12.      tx.commit();  
  13.    }catch (RuntimeException e) {  
  14.      if (tx != null) {  
  15.        tx.rollback();  
  16.      }  
  17.       e.printStackTrace();  
  18.    } finally {  
  19.      session.close();  
  20.    }  
  21.  } 

这样重复执行多余的SQL语句会影响java应用的性能,解决的方法是将<set>的inverse属性设为true。因此修改Customer.hbm.xml文件:

  1. <set   
  2.         name="orders" 
  3.         inverse="true" 
  4.         cascade="save-update"   
  5.         >  
  6.           
  7.         <key column="CUSTOMER_ID" />//表示ORDERS表通过外键CUSTOMER_ID参照CUSTOMERS表  
  8.         <one-to-many class="mypack.Order" />  
  9. </set>  

4)级联删除:

  1. tx = session.beginTransaction();  
  2.       Customer customer=(Customer)session.load(Customer.class,customerId);  
  3.       session.delete(customer);  
  4.       tx.commit(); 

如果要删除Customer所关联的Order对象的话,需要将cascade属性设置为delete,如下:

  1. <set   
  2.        name="orders" 
  3.        inverse="true" 
  4.        cascade="delete"   
  5.        >  
  6. <key column="CUSTOMER_ID" />  
  7.        <one-to-many class="mypack.Order" />  
  8.     </set> 

执行后,Hibernate会做以下动作:

  1. delete from ORDERS where CUSTOMER_ID=2;  
  2. delete from CUSTOMERS where ID=2

如果关联双方是父子关系,就可以把复方的cascade设置为all-delete-orphan;这样删除父方对象时就会级联删除所有关联的子方对象。


相关栏目:

用户点评