日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
精通Hibernate:映射一對多關(guān)聯(lián)關(guān)系

在域模型中,類和類之間最普通的關(guān)系就是關(guān)聯(lián)關(guān)系。在UML語言中,關(guān)聯(lián)是有方向的。以客戶(Customer)和訂單(Order)的關(guān)系為例,一個客戶可以發(fā)出多個訂單,而一個訂單只能屬于一個客戶。

從Order到Customer的關(guān)聯(lián)是多對一關(guān)聯(lián),這意味著每個Order對象都會引用一個Customer對象,因此在Order類中應(yīng)該定義一個Customer類型的屬性,來引用所關(guān)聯(lián)的Customer對象。

從Customer到Order的關(guān)聯(lián)是一對多的關(guān)聯(lián),這意味著每個Customer對象都會引用一組Order對象,因此在Customer類中應(yīng)該定義一個集合類型的屬性,來引用所有關(guān)聯(lián)的Order對象。

一、建立多對一的單向關(guān)聯(lián)關(guān)系

如上例中,我們只需在Order類中定義一個customer屬性,而在Customer類中無需定義存放Order對象的集合屬性。

Order.java

 
 
 
 
  1. package mypack;  
  2.  
  3. public class Order  implements java.io.Serializable {  
  4.      private long id;  
  5.      private String orderNumber;  
  6.      private Customer customer;//定義一個Customer屬性  
  7.  
  8.     public Order() {  
  9.     }  
  10.  
  11.     public Order(Customer customer) {  
  12.         this.customer = customer;  
  13.     }  
  14.     public Order(String orderNumber, Customer customer) {  
  15.        this.orderNumber = orderNumber;  
  16.        this.customer = customer;  
  17.     }  
  18.      
  19.    //省略了id,orderNumber的構(gòu)造方法  
  20.     public Customer getCustomer() {  
  21.         return this.customer;  
  22.     }  
  23.       
  24.     public void setCustomer(Customer customer) {  
  25.         this.customer = customer;  
  26.     }  
  27.  

Customer類的所有屬性都是和CUSTOMERS表中的字段一一對應(yīng),因此可以直接使用如下的映射代碼:

 
 
 
 
  1.  
  2.      
  3.        
  4.      
  5.  
  6.      
  7.          
  8.      
  9.        
  10.   

Order類的orderNumber屬性和ORDERS表中ORDER_NUMBER字段對應(yīng),映射代碼和上面類似,此處省去。我們關(guān)注的主要地方是,Order類中的customer屬性,因為他是Customer類型的,是與ORDERS表的外鍵CUSTOMER_ID對應(yīng)的,它的真實值是存在CUSTOMERS表中而ORDERS表存的只是對它的引用,因此customer的映射方法不能如上面一樣。

 
 
 
 
  1.         name="customer" 
  2.         column="CUSTOMER_ID" 
  3.         class="mypack.Customer" 
  4.         not-null="true"   
  5.         lazy="false" 
  6. /> 

使用方法のBussiness.java演示:

 
 
 
 
  1. package mypack;  
  2.  
  3. import org.hibernate.*;  
  4. import org.hibernate.cfg.Configuration;  
  5. import java.util.*;  
  6.  
  7. public class BusinessService{  
  8.   public static SessionFactory sessionFactory;  
  9.   static{  
  10.      try{  
  11.       // 初始化  
  12.        Configuration config = new Configuration();  
  13.        config.configure();  
  14.        sessionFactory = config.buildSessionFactory();  
  15.     }catch(RuntimeException e){e.printStackTrace();throw e;}  
  16.   }  
  17. /*根據(jù)參數(shù)指定customer的customer_id找出記錄*/ 
  18.   public List findOrdersByCustomer(Customer customer){  
  19.     Session session = sessionFactory.openSession();  
  20.     Transaction tx = null;  
  21.     try {  
  22.       tx = session.beginTransaction();  
  23.  
  24.       List orders=session.createQuery("from Order as o where o.customer.id="+customer.getId())  
  25.                          .list();  
  26.       //Hibernate執(zhí)行:select * from ORDERS where CUSTOMER_ID=customer.getId();  
  27.       tx.commit();  
  28.       return orders;  
  29.     }catch (RuntimeException e) {  
  30.       if (tx != null) {  
  31.         tx.rollback();  
  32.       }  
  33.       throw e;  
  34.     } finally {  
  35.       session.close();  
  36.     }  
  37.   }  
  38. /*根據(jù)OID找出指定customer_id的記錄*/ 
  39.   public Customer findCustomer(long customer_id){  
  40.     Session session = sessionFactory.openSession();  
  41.     Transaction tx = null;  
  42.     try {  
  43.       tx = session.beginTransaction();  
  44.       Customer customer=(Customer)session.get(Customer.class,new Long(customer_id));  
  45.       tx.commit();  
  46.       return customer;  
  47.     }catch (RuntimeException e) {  
  48.       if (tx != null) {  
  49.         tx.rollback();  
  50.       }  
  51.       throw e;  
  52.     } finally {  
  53.       session.close();  
  54.     }  
  55.   }  
  56.  
  57. /*    
  58.     public void saveCustomerAndOrderWithCascade(){  
  59.     Session session = sessionFactory.openSession();  
  60.     Transaction tx = null;  
  61.     try {  
  62.       tx = session.beginTransaction();  
  63.  
  64.       Customer customer=new Customer("Jack");//創(chuàng)建一個Customer持久化對象  
  65.       //不保存customer對象,這樣執(zhí)行的話會出現(xiàn)異常  
  66.       Order order1=new Order("Jack_Order001",customer);  
  67.       Order order2=new Order("Jack_Order002",customer);//創(chuàng)建兩個Order對象  
  68.  
  69.       session.save(order1);  
  70.       session.save(order2);  
  71.  
  72.       tx.commit();  
  73.  
  74.     }catch (RuntimeException e) {  
  75.       if (tx != null) {  
  76.         tx.rollback();  
  77.       }  
  78.       e.printStackTrace();  
  79.     } finally {  
  80.       session.close();  
  81.     }  
  82.   }  
  83.  
  84. */  public void saveCustomerAndOrder(){  
  85.     Session session = sessionFactory.openSession();  
  86.     Transaction tx = null;  
  87.     try {  
  88.       tx = session.beginTransaction();  
  89.  
  90.       Customer customer=new Customer("Tom");//創(chuàng)建一個Customer持久化對象  
  91.       session.save(customer);  
  92.  
  93.       Order order1=new Order("Tom_Order001",customer);  
  94.       Order order2=new Order("Tom_Order002",customer);//創(chuàng)建兩個Order對象  
  95.       session.save(order1);  
  96.       session.save(order2);  
  97.      // 對同一個customerHibernate執(zhí)行兩次插入ORDERS表  
  98.       tx.commit();  
  99.  
  100.     }catch (RuntimeException e) {  
  101.       if (tx != null) {  
  102.         tx.rollback();  
  103.       }  
  104.       throw e;  
  105.     } finally {  
  106.       session.close();  
  107.     }  
  108.   }  
  109.     
  110.   public void printOrders(List orders){  
  111.       for (Iterator it = orders.iterator(); it.hasNext();) {  
  112.          Order order=(Order)it.next();  
  113.          System.out.println("OrderNumber of "+order.getCustomer().getName()+ " :"+order.getOrderNumber());  
  114.       }  
  115.   }  
  116.  
  117.    public void test(){  
  118.       saveCustomerAndOrder();  
  119.     //  saveCustomerAndOrderWithCascade();  
  120.       Customer customer=findCustomer(1);  
  121.       List orders=findOrdersByCustomer(customer);  
  122.       printOrders(orders);  
  123.   }  
  124.  
  125.   public static void main(String args[]){  
  126.     new BusinessService().test();  
  127.     sessionFactory.close();  
  128.   }  
  129. }  
  130.  
  131.  

上述代碼中方法 saveCustomerAndOrderWithCascade()如果沒有session.save(customer)這一句,

執(zhí)行時會拋出PropertyValueException異常,主要原因是:

在調(diào)用session.save(order1)方法之前,order1和customer對象都是臨時的,臨時對象是由new創(chuàng)建的,都是沒有持久化的對象。假設(shè) session.save(order1)被成功執(zhí)行,order1會被成功持久化,變成持久化對象,但是Hibernate不會自動持久化order1所關(guān)聯(lián)的customer對象。

在執(zhí)行session.save(order1)時,插入ORDERS表記錄的CUSTOMER_ID字段為null,這違反了數(shù)據(jù)庫完整性約束,即ORDERS表中不允許CUSTOMER_ID為null。

疑問假設(shè)ORDERS表中CUSTOMER_ID字段允許為null:

 
 
 
 
  1.         name="customer" 
  2.         column="CUSTOMER_ID" 
  3.         class="mypack.Customer" 
  4.         not-null="false"   
  5.         lazy="false" 
  6.      /> 

這樣執(zhí)行的話,能夠成功的向ORDERS表中插入兩條數(shù)據(jù);但是當(dāng)Hibernate自動清理(flush)緩存中所有持久化對象時,又會拋出新的異常

 
 
 
 
  1. org.hibernate.TransientObjectException:object references an unsaved transient instance -save the transient instance before flushing :mypack.Customer 

所謂清理是指Hibernate按照持久化對象的屬性變化來同步更新數(shù)據(jù)庫。在清理的時候Hibernate會發(fā)現(xiàn)order1和order2都引用臨時對象customer,而在ORDERS表中CUSTOMER_ID字段為null,這就意味著內(nèi)存中持久化對象的屬性和數(shù)據(jù)庫中記錄不一致。之所以會報錯是因為order1中customer屬性引用了一個臨時對象Customer。

由此可見,Hibernate持久化一個對象時,默認(rèn)情況下不會自動持久化所關(guān)聯(lián)的其他對象。但是,我們我們希望當(dāng)Hibernate持久化Order對象時自動持久化所關(guān)聯(lián)的Customer對象,我們可以修改映射文件如下:

 
 
 
 
  1.         name="customer" 
  2.         column="CUSTOMER_ID" 
  3.         class="mypack.Customer" 
  4.         cascade="save-update" 
  5.         not-null="false"   
  6.         lazy="false" 
  7.      /> 

當(dāng)cascade屬性為“save-update”,表明保存或更新對象時,會級聯(lián)保存或更新與它所關(guān)聯(lián)的對象。如上例中,執(zhí)行saveCustomerAndOrderWithCascade()時,Hibernate會把order1與customer對象一起持久化,此時Hibernate會執(zhí)行

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

#p#

二、映射一對多雙向關(guān)聯(lián)關(guān)系

類類之間建立了聯(lián)系,就可以很方便地從一個對象導(dǎo)航到另一個或者另一組與它相關(guān)聯(lián)的對象。正如上例中,對于給定的Order對象,如果想獲得與之關(guān)聯(lián)的Customer對象,可以直接如下調(diào)用:

 
 
 
 
  1. Customer customer=order.getCustomer(); 

那么對于給定的Customer對象,如何一次獲得所有與之關(guān)聯(lián)的Order對象呢?由于上例中Customer對象沒有和Order對象關(guān)聯(lián),我們也可以通過Hibernate API去查詢數(shù)據(jù)庫:

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

顯然這樣做的效率會很低,而且復(fù)雜的關(guān)聯(lián)關(guān)系也會給編程帶來影響。我們可以為Customer類和Order類簡歷一對多的雙向關(guān)聯(lián)。

第一部分我們已經(jīng)建立了Order類和Customer類的多對一關(guān)聯(lián),現(xiàn)在我們再增加Customer到Order類的一對多關(guān)聯(lián)。

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();//初始化為集合實現(xiàn)類,這樣做可以提高程序的健壯性,同時避免了應(yīng)用程序訪問取詞為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.  
  2.     
  3.       
  4.     
  5.  
  6.     
  7.         
  8.     
  9.   
  10.       name="orders" 
  11.       cascade="save-update"   
  12.         
  13.         
  14.       //表示ORDERS表通過外鍵CUSTOMER_ID參照CUSTOMERS表  
  15.         
  16.         
  17.  
  18.  

使用方法のBussiness.java演示分函數(shù)介紹:

(1)saveCustomerAndOrderWithCascade()方法:當(dāng)映射文件中的屬性為“save-update”時,Hibernate在持久化Customer對象時也會自動持久化其所關(guān)聯(lián)的Order對象

 
 
 
 
  1.   public void saveCustomerAndOrderWithCascade(){  
  2.     Session session = sessionFactory.openSession();  
  3.     Transaction tx = null;  
  4.     try {  
  5.       tx = session.beginTransaction();  
  6. /*創(chuàng)建一個customer對象和order對象*/ 
  7.       Customer customer=new Customer("Tom",new HashSet());  
  8.       Order order=new Order();  
  9.       order.setOrderNumber("Tom_Order001");  
  10. /*建立Customer與Order的一對多雙向關(guān)聯(lián)關(guān)系*/ 
  11.       order.setCustomer(customer);  
  12.       customer.getOrders().add(order);  
  13. /*保存Customer對象*/ 
  14.       session.save(customer);  
  15. /* 當(dāng)映射文件中的屬性為“save-update”時,Hibernate在持久化Customer對象時也會自動持久化其所關(guān)聯(lián)的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.   } 

當(dāng)映射文件中的屬性為“save-update”時,Hibernate在持久化Customer對象時也會自動持久化其所關(guān)聯(lián)的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關(guān)聯(lián)的所有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.   }  

其調(diào)用的函數(shù)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()方法:演示映射文件屬性為inverse

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

調(diào)用的函數(shù)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);   
  7. tx.commit();  
  8. idOfJack=customer.getId();  
  9. idOfJackOrder=order.getId(); 

為了使上述代碼正常執(zhí)行,需要確保Order.hbm.xml文件的元素的not null取默認(rèn)值false,否則會出現(xiàn)異常;Hibernate會執(zhí)行如下

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

調(diào)用的函數(shù)associateCustomerAndOrder():該方法加載由saveCustomerAndOrderSeparately()方法持久化Customer和Order對象,然后建立兩者之間的一對多的關(guān)系

 
 
 
 
  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的關(guān)聯(lián)關(guān)系*/ 
  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.  } 

這樣重復(fù)執(zhí)行多余的SQL語句會影響java應(yīng)用的性能,解決的方法是將的inverse屬性設(shè)為true。因此修改Customer.hbm.xml文件:

 
 
 
 
  1.         name="orders" 
  2.         inverse="true" 
  3.         cascade="save-update"   
  4.         >  
  5.           
  6.         //表示ORDERS表通過外鍵CUSTOMER_ID參照CUSTOMERS表  
  7.           
  8.   

(4)級聯(lián)刪除:

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

如果要刪除Customer所關(guān)聯(lián)的Order對象的話,需要將cascade屬性設(shè)置為delete,如下:

 
 
 
 
  1.        name="orders" 
  2.        inverse="true" 
  3.        cascade="delete"   
  4.        >  
  5.  
  6.          
  7.      

執(zhí)行后,Hibernate會做以下動作:

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

如果關(guān)聯(lián)雙方是父子關(guān)系,就可以把復(fù)方的cascade設(shè)置為all-delete-orphan;這樣刪除父方對象時就會級聯(lián)刪除所有關(guān)聯(lián)的子方對象。

#p#

三、映射一對多雙向自身關(guān)聯(lián)關(guān) 

Category.java:

 
 
 
 
  1. package mypack;  
  2. import java.util.HashSet;  
  3. import java.util.Set;  
  4. public class Category  implements java.io.Serializable {  
  5.      private long id;  
  6.      private String name;  
  7.      private Set childCategories = new HashSet(0);  
  8.      private Category parentCategory;  
  9.  
  10.     public Category() {  
  11.     }  
  12.  
  13.     public Category(String name, Set childCategories, Category parentCategory) {  
  14.        this.name = name;  
  15.        this.childCategories = childCategories;  
  16.        this.parentCategory = parentCategory;  
  17.     }  
  18.      
  19.     public long getId() {  
  20.         return this.id;  
  21.     }  
  22.       
  23.     public void setId(long id) {  
  24.         this.id = id;  
  25.     }  
  26.     public String getName() {  
  27.         return this.name;  
  28.     }  
  29.       
  30.     public void setName(String name) {  
  31.         this.name = name;  
  32.     }  
  33.     public Set getChildCategories() {  
  34.         return this.childCategories;  
  35.     }  
  36.       
  37.     public void setChildCategories(Set childCategories) {  
  38.         this.childCategories = childCategories;  
  39.     }  
  40.     public Category getParentCategory() {  
  41.         return this.parentCategory;  
  42.     }  
  43.       
  44.     public void setParentCategory(Category parentCategory) {  
  45.         this.parentCategory = parentCategory;  
  46.     }  

配置文件Category.hbm.xml:

 
 
 
 
  1.  
  2. PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4.  
  5.  
  6.     
  7.       
  8.         
  9.       
  10.  
  11.       
  12.           
  13.       
  14.  
  15.     
  16.         name="childCategories" 
  17.         cascade="save-update" 
  18.         inverse="true" 
  19.         >  
  20.           
  21.           
  22.           
  23.  
  24.    
  25.         name="parentCategory" 
  26.         column="CATEGORY_ID" 
  27.         class="mypack.Category" 
  28.        />  
  29.  
  30.     
  31.  
  32.  

分享標(biāo)題:精通Hibernate:映射一對多關(guān)聯(lián)關(guān)系
標(biāo)題網(wǎng)址:http://www.5511xx.com/article/dpohooe.html