Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么

這篇文章主要講解了“Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么”吧!

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、成都小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了濂溪免費(fèi)建站歡迎大家使用!

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

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

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

Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么

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

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

Order.java

package mypack;   public class Order  implements java.io.Serializable {       private long id;       private String orderNumber;       private Customer customer;//定義一個(gè)Customer屬性       public Order() {      }       public Order(Customer customer) {          this.customer = customer;      }      public Order(String orderNumber, Customer customer) {         this.orderNumber = orderNumber;         this.customer = customer;      }          //省略了id,orderNumber的構(gòu)造方法      public Customer getCustomer() {          return this.customer;      }            public void setCustomer(Customer customer) {          this.customer = customer;      }   }

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

<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>

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

<many-to-one          name="customer"         column="CUSTOMER_ID"         class="mypack.Customer"         not-null="true"           lazy="false" />

使用方法のBussiness.java演示:

package mypack;   import org.hibernate.*;  import org.hibernate.cfg.Configuration;  import java.util.*;   public class BusinessService{    public static SessionFactory sessionFactory;    static{       try{        // 初始化         Configuration config = new Configuration();         config.configure();         sessionFactory = config.buildSessionFactory();      }catch(RuntimeException e){e.printStackTrace();throw e;}    }  /*根據(jù)參數(shù)指定customer的customer_id找出記錄*/   public List findOrdersByCustomer(Customer customer){      Session session = sessionFactory.openSession();      Transaction tx = null;      try {        tx = session.beginTransaction();         List orders=session.createQuery("from Order as o where o.customer.id="+customer.getId())                           .list();        //Hibernate執(zhí)行:select * from ORDERS where CUSTOMER_ID=customer.getId();        tx.commit();        return orders;      }catch (RuntimeException e) {        if (tx != null) {          tx.rollback();        }        throw e;      } finally {        session.close();      }    }  /*根據(jù)OID找出指定customer_id的記錄*/   public Customer findCustomer(long customer_id){      Session session = sessionFactory.openSession();      Transaction tx = null;      try {        tx = session.beginTransaction();        Customer customer=(Customer)session.get(Customer.class,new Long(customer_id));        tx.commit();        return customer;      }catch (RuntimeException e) {        if (tx != null) {          tx.rollback();        }        throw e;      } finally {        session.close();      }    }   /*        public void saveCustomerAndOrderWithCascade(){      Session session = sessionFactory.openSession();      Transaction tx = null;      try {        tx = session.beginTransaction();         Customer customer=new Customer("Jack");//創(chuàng)建一個(gè)Customer持久化對象        //不保存customer對象,這樣執(zhí)行的話會出現(xiàn)異常        Order order1=new Order("Jack_Order001",customer);        Order order2=new Order("Jack_Order002",customer);//創(chuàng)建兩個(gè)Order對象         session.save(order1);        session.save(order2);         tx.commit();       }catch (RuntimeException e) {        if (tx != null) {          tx.rollback();        }        e.printStackTrace();      } finally {        session.close();      }    }   */  public void saveCustomerAndOrder(){      Session session = sessionFactory.openSession();      Transaction tx = null;      try {        tx = session.beginTransaction();         Customer customer=new Customer("Tom");//創(chuàng)建一個(gè)Customer持久化對象        session.save(customer);         Order order1=new Order("Tom_Order001",customer);        Order order2=new Order("Tom_Order002",customer);//創(chuàng)建兩個(gè)Order對象        session.save(order1);        session.save(order2);       // 對同一個(gè)customerHibernate執(zhí)行兩次插入ORDERS表        tx.commit();       }catch (RuntimeException e) {        if (tx != null) {          tx.rollback();        }        throw e;      } finally {        session.close();      }    }        public void printOrders(List orders){        for (Iterator it = orders.iterator(); it.hasNext();) {           Order order=(Order)it.next();           System.out.println("OrderNumber of "+order.getCustomer().getName()+ " :"+order.getOrderNumber());        }    }      public void test(){        saveCustomerAndOrder();      //  saveCustomerAndOrderWithCascade();        Customer customer=findCustomer(1);        List orders=findOrdersByCustomer(customer);        printOrders(orders);    }     public static void main(String args[]){      new BusinessService().test();      sessionFactory.close();    }  }  <span style="font-size:16px;color:#cc33cc;"><strong>  </strong></span>

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

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

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

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

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

<many-to-one          name="customer"         column="CUSTOMER_ID"         class="mypack.Customer"         not-null="false"           lazy="false"      />

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

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

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

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

<many-to-one          name="customer"         column="CUSTOMER_ID"         class="mypack.Customer"         cascade="save-update"         not-null="false"           lazy="false"      />

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

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

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

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

Customer customer=order.getCustomer();

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

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文件:

package mypack;  import java.util.HashSet;   import java.util.Set;  //Hibernate要求在持久化類中定義集合類屬性時(shí),必須要把屬性聲明為接口類型。   public class Customer  implements java.io.Serializable {       private long id;       private String name;       private Set orders = new HashSet();//初始化為集合實(shí)現(xiàn)類,這樣做可以提高程序的健壯性,同時(shí)避免了應(yīng)用程序訪問取詞為null的orders集合的方法而拋出NullPointerException。      public Customer() {      }       public Customer(String name, Set orders) {         this.name = name;         this.orders = orders;      }     //省略了id,name的get和set訪問方法      public Set getOrders() {          return this.orders;      }            public void setOrders(Set orders) {          this.orders = orders;      }  }

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

<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" />//表示ORDERS表通過外鍵CUSTOMER_ID參照CUSTOMERS表        <one-to-many class="mypack.Order" />     </set>      </class>

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

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

  public void saveCustomerAndOrderWithCascade(){      Session session = sessionFactory.openSession();      Transaction tx = null;      try {        tx = session.beginTransaction();  /*創(chuàng)建一個(gè)customer對象和order對象*/       Customer customer=new Customer("Tom",new HashSet());        Order order=new Order();        order.setOrderNumber("Tom_Order001");  /*建立Customer與Order的一對多雙向關(guān)聯(lián)關(guān)系*/       order.setCustomer(customer);        customer.getOrders().add(order);  /*保存Customer對象*/       session.save(customer);  /* 當(dāng)映射文件中<set>的屬性為“save-update”時(shí),Hibernate在持久化Customer對象時(shí)也會自動持久化其所關(guān)聯(lián)的Order對象   insert into CUSTOMERS(ID,NAME) values(1,"Tom");   insert into ORDERS(ID,ORDER_NUMBER,CUSTOMER_ID) values(1,"Tom_Order001",1)*/       tx.commit();        idOfTom=customer.getId();        idOfTomOrder=order.getId();                            }catch (RuntimeException e) {        if (tx != null) {          tx.rollback();        }        e.printStackTrace();      } finally {        session.close();      }    }

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

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

(2)printOrdersOfCustomer(Long customerId)方法:打印與指定customerId關(guān)聯(lián)的所有Order對象

public void printOrdersOfCustomer(Long customerId){    Session session = sessionFactory.openSession();    Transaction tx = null;    try {      tx = session.beginTransaction();      Customer customer=(Customer)session.get(Customer.class,customerId);      printOrders(customer.getOrders());//使用getOrders獲取一個(gè)order對象set      tx.commit();    }catch (RuntimeException e) {      if (tx != null) {         tx.rollback();      }      throw e;    } finally {       session.close();    }  }

其調(diào)用的函數(shù)printOrders(Set orders)

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

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

public void saveCustomerAndOrderWithInverse(){        saveCustomerAndOrderSeparately();        associateCustomerAndOrder();     }

調(diào)用的函數(shù)saveCustomerAndOrderSeparately():即是分別存儲,與saveCustomerAndOrderWithCascade()方法恰好相反。

Customer customer=new Customer();  customer.setName("Jack");  Order order=new Order();  order.setOrderNumber("Jack_Order001");  session.save(customer);  session.save(order);&nbsp;  tx.commit();  idOfJack=customer.getId();  idOfJackOrder=order.getId();

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

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

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

public void associateCustomerAndOrder(){     Session session = sessionFactory.openSession();     Transaction tx = null;     try {       tx = session.beginTransaction();       /*加載持久化對象Customer、Order*/      Customer customer=(Customer)session.load(Customer.class,idOfJack);       Order order=(Order)session.load(Order.class,idOfJackOrder);       /*建立Customer和Order的關(guān)聯(lián)關(guān)系*/      order.setCustomer(customer);       customer.getOrders().add(order);       tx.commit();     }catch (RuntimeException e) {       if (tx != null) {         tx.rollback();       }        e.printStackTrace();     } finally {       session.close();     }   }

Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么

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

<set           name="orders"         inverse="true"         cascade="save-update"           >                    <key column="CUSTOMER_ID" />//表示ORDERS表通過外鍵CUSTOMER_ID參照CUSTOMERS表          <one-to-many class="mypack.Order" />  </set>

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

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

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

<set          name="orders"        inverse="true"        cascade="delete"          >  <key column="CUSTOMER_ID" />         <one-to-many class="mypack.Order" />      </set>

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

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

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

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

Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么

Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么

Category.java:

package mypack;  import java.util.HashSet;  import java.util.Set;  public class Category  implements java.io.Serializable {       private long id;       private String name;       private Set childCategories = new HashSet(0);       private Category parentCategory;       public Category() {      }       public Category(String name, Set childCategories, Category parentCategory) {         this.name = name;         this.childCategories = childCategories;         this.parentCategory = parentCategory;      }           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 getChildCategories() {          return this.childCategories;      }            public void setChildCategories(Set childCategories) {          this.childCategories = childCategories;      }      public Category getParentCategory() {          return this.parentCategory;      }            public void setParentCategory(Category parentCategory) {          this.parentCategory = parentCategory;      }  }

配置文件Category.hbm.xml:

<?xml version="1.0"?>  <!DOCTYPE hibernate-mapping  PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  <hibernate-mapping >     <class name="mypack.Category" table="CATEGORIES" >      <id name="id" type="long" column="ID">        <generator class="increment"/>      </id>       <property name="name" type="string" >          <column name="NAME" length="15" />      </property>       <set           name="childCategories"         cascade="save-update"         inverse="true"         >          <key column="CATEGORY_ID" />          <one-to-many class="mypack.Category" />       </set>         <many-to-one          name="parentCategory"         column="CATEGORY_ID"         class="mypack.Category"        />     </class>   </hibernate-mapping>

感謝各位的閱讀,以上就是“Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

文章名稱:Hibernate映射一對多關(guān)聯(lián)關(guān)系是什么
文章分享:http://muchs.cn/article2/gjghoc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、自適應(yīng)網(wǎng)站、品牌網(wǎng)站制作、網(wǎng)站維護(hù)、用戶體驗(yàn)、定制網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管