標籤:style class blog c code java
上篇文章討論了雙向關聯的一對一映射,用了兩個章節,主要是從主鍵和外鍵兩種關聯映射展開詳細討論,雙向關聯的映射需要在兩個對應檔中分別添加相互的對應關係,斌剛在相應的類中添加對應的關聯類別的屬性,這樣在一端載入時才能載入到另一端的對象。關聯中常用的主要有多對一、一對一、一對多和多對多,我們已經討論了兩種映射關係,接下來將會討論一對多的關係。
一、單向一對多
前篇文章中曾經對多對一的關係展開了討論,其中主要使用的是<many-to-one>的關係,在多的一端維護一的一端,那和今天要討論的一對多的關係它們之間是否有關聯呢?在關係和物件模型中存在了一對多關聯性所以理所當然就會有多對一的關係,Hibernate同樣提供了一對多關聯性的標籤<one-to-many>。 一對多關聯性的物件模型在日常生活中也經常看到,就拿學生和班級來說,一個班級裡有多個學生,所以班級和學生的關係是一對多的關係,映射到物件模型中,如:
物件模型說明了這種一對多的關係是由一的一端來維護的,那麼映射成關聯式模式就是一個班級欄位下面會有多個學生,這樣就形成了一對多的關係,通過班級能夠查詢獲得學生資訊,對應的關聯式模式如:
1、基本配置
有了物件模型接下來就讓它們映射為對應的關係代碼,在進行關係映射時需要在一的一端添加<one-to-many>標籤,另外還需要在一的一端添加Set屬性,它支援消極式載入,然後在對應檔添加set標籤,並指明一對多的關係,這樣就能夠在一的一端查詢擷取多的一端。
Classes類及對應檔 它是模型中最重要的一端,在該端需要添加對應的set屬性,並在設定檔中添加set標籤,在set標籤中配置相應的<one-to-many>對象,具體Classes.java對象代碼如下:
<pre name="code" class="java">package com.src.hibernate;import java.util.Set;public class Classes {private int id;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}private String name;//Set支援消極式載入private Set students;public Set getStudents() {return students;}public void setStudents(Set students) {this.students = students;}}
Classes對象中使用了set屬性,但是只是說明了消極式載入的屬性,並沒有為屬性配置對應的對象,屬性的對象是要在對應檔中來配置的,需要添加set標籤,並在set標籤中添加<one-to-many>標籤,具體如下代碼:
<?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="com.hibernate.Classes" table="t_classes"><id name="id"><generator class="native"/></id><property name="name"/><set name="students"><key column="classesid"></key><one-to-many class="com.hibernate.Student"></one-to-many></set></class></hibernate-mapping>
對應的Student對象中的代碼和對應檔不需要什麼特殊的配置,只需要按照通常的寫法編寫即可,具體的配置方法不再詳述,很簡單。配置好後需要產生對應的SQL語句,將物件模型轉化為關聯式模式時Hibernate產生相應的語句如下:
alter table t_student drop foreign key FK4B9075705E0AFEFEdrop table if exists t_classesdrop table if exists t_studentcreate table t_classes (id integer not null auto_increment, name varchar(255), primary key (id))create table t_student (id integer not null auto_increment, name varchar(255), classesid integer, primary key (id))alter table t_student add index FK4B9075705E0AFEFE (classesid), add constraint FK4B9075705E0AFEFE foreign key (classesid) references t_classes (id)
產生的對應的關聯式模式如:
對比SQL語句和關聯式模式,相應的表之間的關聯是通過外鍵來維護的,首先是建立兩張表,並指定表的主鍵,最後添加一對多的外部索引鍵關聯關係。
2、基本操作 在對資料庫的操作無非是讀和寫兩種,修改也屬於寫的一種,接下來看看是如何向資料庫中寫入和讀取操作的。
寫入資料 寫入資料需要注意的是一對多的關係,所以在添加的時候需要添加多個學生類,另外由於在classes中添加了對應的set屬性,所以在添加Student對象時應該使用HashSet來添加,這樣既可實現一對多的關係,具體如下代碼:
public void testSave2(){Session session=null;try{session=HibernateUtils.getSession();session.beginTransaction();Student student1=new Student();student1.setName("zhangsan");session.save(student1);Student student2=new Student();student2.setName("lisi");session.save(student2);Classes classes=new Classes();classes.setName("ClassOne");Set students=new HashSet();students.add(student1);students.add(student2);classes.setStudents(students);//可以成功儲存資料//但是會發出多餘的update語句來維持關係,因為是一對多的原因session.save(classes);session.getTransaction().commit();}catch(Exception e){e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}
那麼運行上面的測試案例產生的對應的資料寫入到資料庫中後如:
讀取資料 寫入操作相對簡單,只需要把所有載入的對象都添加到Transient狀態下,運行相應的方法就可以插入內容,但是對應的讀取操作就會稍微複雜點,因為需要迭代擷取所有的學生對象,所以這種一對多的關係效率並不很高,具體代碼如下:
package com.test.hibernate;import java.util.Iterator;import java.util.Set;import com.src.hibernate.*;import junit.framework.TestCase;import org.hibernate.Session;public class One2ManyTest extends TestCase {public void testLoad1(){Session session=null;try{session=HibernateUtils.getSession();session.beginTransaction();//擷取主鍵為5的班級資訊Classes classes=(Classes)session.load(Classes.class,5);//列印班級資訊System.out.println("classes.name="+classes.getName());//設定學生集合,通過班級載入學生集合Set students=classes.getStudents();//迭代集合,列印集合中學生的資訊for(Iterator iter=students.iterator();iter.hasNext();){Student student=(Student)iter.next();System.out.println("student.name="+student.getName());}session.getTransaction().commit();}catch(Exception e){e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}}
產生的相應的語句及資訊如下語句:
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?classes.name=ClassOneHibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_ from t_student students0_ where students0_.classesid=?student.name=lisistudent.name=zhangsan
結語
一對多的關係也是經常用到的,但是這種關係在載入時效率會不高,因為需要維護的資料較多,所以不建議使用一對多的關係,可以考慮多對一的關係,這樣在載入時其實是一種一對一的關係,載入的效率較高,關係和物件模型得到了最佳化。這裡只是討論了單向的一對多,下篇文章討論雙向的關聯關係。