淺談JavaEE中的Hibernate中的四種關係對映(三)
今天我們一起來探討一下有關Hibernate四種關係對映,大家可能會有疑惑,關係對映不就是隻有三種(一對一,一對多,多對多)嗎?這裡我們再多說一個繼承對映關係,雖然它使用頻繁度沒有前三個那麼多,但是它在一些特定情況下,還是非常有用的,至於有什麼用下面馬上就要講。這些關係對映實際上就是對應著關係型資料庫中的幾種關係的型別。我們都知道Hibernate的作用是將面向關係資料操作,轉換成面向物件的操作,其中關係對映檔案就是實現這個轉換的核心。我們都知道如果我們僅僅使用SQL語句建表並且去維護表與表之間一對一,一對多,多對多關係,這樣單純SQL操作是很簡單的。我們通過上篇部落格就知道我們要實現的是寫好Bean類,然後對應配置好相應的對映檔案,執行測試類後就可以實現自動在資料庫建立資料表。而我們現在就要實現,如何利用Bean類和對映檔案自動建立多個表,並且還要體現出多個表之間的一對一,一對多,多對多的關係。
說白的一點,就是要通過編寫多個不同的Bean類(一個Bean類就是對應一張表),和配置對映檔案,實現自動建立帶有關係(一對一、一對多、多對多關係)的資料表。那我們開始第一個。
實際上通過我們上篇部落格我們不難發現,實現表的建立主要體現兩個方面,一個是Bean類(兩個Bean類之間首先要區分:主表類和從表類),另一個則是Bean類對應的對映檔案(首先需要區分:主方和從方),所以接下來的每一種對映關係的討論也將圍繞著這幾個方面來展開。
第一種關係:如何去自動建立一個一對一的關係資料表:
注意:在建立一對一對映關係的資料表,實際上有兩種方法來實現:一種是通過主鍵來對映關係,另一種則是通過外來鍵來對映關係。
第一種實現方式:通過主鍵的方式對映關係:實際上就是通過主表的主鍵來生成從表的主鍵,這就是所謂主鍵生成方式,也就是從表的主鍵生成機制是有限制,必須要參照主表的中的主鍵,不可能出現主表中不存在的主鍵。然後通過主表的主鍵來尋找從表的主鍵,由於主鍵是不可能重複,所以也就形成通過主鍵的對映方式來實現和維護了兩個表之間的一對一的關係。
1、在Bean類中的體現:假如有Person類和Card類兩個Bean類,來自動建立兩張具有一對一關係的資料表。Person類為主方,Card類為從方
這裡面還分為單向維護和雙向維護,單向維護就是在主方類中儲存一個從方類中的引用或者在從方類中儲存一個主方類的引用。為了講解全面點,我們全都以雙向維護為例。
可能有人會有疑問,什麼是單向維護什麼又是雙向維護,單向維護可以通過維護的主動方來找到被維護的一方;而雙向維護則是雙方都能互相找到。
Person類
package com.mikyou.day05.one2one;
/**
* @Mikyou
* @Person主方類
* 注意:
* 1、在編寫Person類時,不要把從方類的引用寫入到構造器中
* 2、兩個構造器:一個無引數構造器,另一個則是有引數的構造器
* 3、在重寫toString方法的時候,注意不要把從方表引用寫進去。
* */
public class Person {
private Long id;
private String name;
private Card card;//儲存著從方類Card的一個引用
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
public Person(Long id, String name) {
super();
this.id = id;
this.name = name;
}
public Person() {
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", card=" + card + "]";
}
}
Card類:
package com.mikyou.day05.one2one;
/**
* @Mikyou
* @Card從方類
* 注意:
* 1、在編寫Card類時,不要把主方類的引用寫入到構造器中
* 2、兩個構造器:一個無引數構造器,另一個則是有引數的構造器
* 3、在重寫toString方法的時候,注意不要把主方表引用寫進去。
* */
public class Card {
private Long id;
private String num;//身份證號
private String address;//地址
private Person person;//儲存主方類的一個引用
public Card(Long id, String num, String address) {
super();
this.id = id;
this.num = num;
this.address = address;
}
public Card() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNum() {
return num;
}
public void setNum(String num) {
this.num = num;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
2、在對映檔案中的體現:
主方表對映檔案person.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.one2one">
<class name="Person" table="tbl_person">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<!-- 在主方一對一 配置one-to-one-->
<one-to-one name="card" class="Card" />
</class>
</hibernate-mapping>
從方類的對映檔案card.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.one2one">
<class name="Card" table="tbl_card">
<id name="id" column="id" >
<generator class="foreign"><!-- 以外來鍵的形式來產生主鍵 -->
<param name="property">person</param>
</generator>
</id>
<property name="num" />
<property name="address" />
<one-to-one name="person" class="Person" constrained="true"></one-to-one><!-- constrained="true"表示從表中的主鍵必須依賴主表中的主鍵 -->
</class>
</hibernate-mapping>
注意:在配置主鍵關係來維護一對一的關係的時候,在對映檔案中的表現,首先雙方都通過<one-to-one>來維護關係。在主方person.hbm.xml對映檔案中
配置<one-to-one name="card" class="Card" />其中的name對應著Person類中儲存的card引用,然後對應card引用的Class,Card類。在從方card.hbm.xml對映檔案中也是配置
<one-to-one>但是需要加上constrained="true"屬性,表示從表card主鍵必須依賴主表person的主鍵,此外在card.hbm.xml中它的主鍵生成方式不再是increment自增的方式了,而是<id name="id" column="id" ><generator class="foreign"><!-- 以外來鍵的形式來產生主鍵 --><param name="property">person</param><!-- --></generator></id>
從表中的主鍵引用了主表中的主鍵,所以需要在主鍵生成方式中設定成foreign,並將引數傳進去,告訴hibernate應該使用哪一個主鍵。在配置上,雙方都為one-to-one
第二種實現方式:通過外來鍵來對映關係:(注意:只要是通過外來鍵來對映關係的,必須在主表和從表中都要有體現)
這第二種方式可以說是維護一對一關係常用的方式,第一種通過主鍵來對映的方式使用的情況不是很多。通過外來鍵來對映關係主要是通過對映檔案來體現的,它的Bean類表現形式和第一種情況一致。它的對映檔案主要怎麼體現呢?它是在主方表中配置一個<one-to-one>並且要新增一個屬性<propery-ref>,在從表中配置一個<many-to-one>,為什麼要配置一個<many-to-one>這不是一對多嗎?我們知道一對一實際上就是一對多的一個特例,所以我們可以將一個一對多的情況轉換成一個一對一的情況只需要在從表中的<many-to-one>中配置一個unique屬性設為true即可並且還得指定一個屬性作為外來鍵通過column屬性來指定,但這種方式下的主鍵生成方式沒有要求就採取自增方式即可。
person.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.one2one">
<class name="Person" table="tbl_person">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<!-- 在主方一對一,因為在主表和從表都要有體現,使用property-ref="person" 因為Card類中參考的是person屬性,通過從表中的外來鍵去匹配主表中主鍵-->
<one-to-one name="card" class="Card" property-ref="person" />
</class>
</hibernate-mapping>
card.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.one2one">
<class name="Card" table="tbl_card">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="num" />
<property name="address" />
<!-- 配置特殊的多對一,實際上是一對一-->
<many-to-one name="person" class="Person" unique="true" column="p_id"></many-to-one>
</class>
</hibernate-mapping>
注意:注意:unique="true" 是在使用hibernate的自動建表的時候才用到,用來指定表中的外來鍵唯一,即給表中的外來鍵新增唯一性約束,保證是一對一的關係
property-ref="" 用來指定關聯類的屬性名,這個屬性將會和本類中的主鍵相對應,如果沒有指定,預設使用關聯類的主鍵和本類中的主鍵相對應。
在一對一關係中,如果沒有在<one-to-one>中指定property-ref="person",當從主方物件尋找從方物件的時候將會使用自身的主鍵和關聯類的主鍵匹配,這樣就會出問題!如果指定後,將會用自身的主鍵和關聯類的外來鍵匹配。property-ref=""中的值為屬性。
第二種關係:如何去自動建立一個一對多的關係資料表(以一個顧客對應多個訂單為例):
1、在Bean類中的表現:
在主類Customer中的表現:在Customer中儲存一個Set<Oder>集合表示一對多在從類Order中儲存一個Customer類的引用
Customer類:
package com.mikyou.day05.one2many;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class Customer implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private String telephone;
private String address;
private String pwd;
private Set<Order> orders=new HashSet<Order>();//維護多個訂單。注意這裡一定要初始化,因為集合中資料為空和
//集合不存在是兩個概念,集合中資料為空表示此時顧客中沒有訂單,當下次來了訂單直接放入到集合中即可
//集合不存在就不行,如果下次只有來了訂單,而此時集合不存在,會造成集合中不能放入訂單物件,造成空指標
public Customer(Long id, String name,String pwd, String telephone, String address) {
super();
this.id = id;
this.name = name;
this.telephone = telephone;
this.address = address;
this.pwd = pwd;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public Customer() {
// TODO Auto-generated constructor stub
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
Order類:
package com.mikyou.day05.one2many;
import java.io.Serializable;
import java.util.Date;
public class Order implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String total;
private Date orderDate;
private Customer customer;//維護主表一方的引用
public Order(Long id, String total, Date orderDate) {
super();
this.id = id;
this.total = total;
this.orderDate = orderDate;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public Order() {
super();
}
@Override
public String toString() {
return "Order [id=" + id + ", total=" + total + ", orderDate=" + orderDate + "]";
}
}
2、在對映檔案中的表現:
customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.one2many">
<class name="Customer" table="tbl_customer">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<property name="telephone" />
<property name="pwd"></property>
<property name="address" />
<!-- 關聯對映 -->
<set name="orders" lazy="true" cascade="delete"><!-- lazy:true延遲載入 預設 cascade="delete"級聯刪除-->
<key column="c_id"></key><!-- 在Order多的一方配置外來鍵 -->
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
order.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.one2many">
<class name="Order" table="tbl_order">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="total" />
<property name="orderDate" />
<!-- 關聯對映,column是與生成表中的一列 -->
<many-to-one name="customer" class="Customer" column="c_id"></many-to-one>
</class>
</hibernate-mapping>
對映一對多關聯
資料庫表中的關係:一個顧客對應多個訂單 |
|
主表:d_customer( Id name ); |
從表: d_order( Id name c_id references d_customer(id) ); 從表的主鍵引用主表的主鍵 |
類中的關係: 雙向維護 |
|
主類 Customer{ Id name Set<Order> orders = new HashSet<>() } 一個顧客對應多個訂單,所以在物件中需要用一個集合來維護,後期可以通過getter方法獲取屬於該顧客的所有訂單 |
從類:Order{ Id name Customer customer } 一個訂單隻能屬於一個顧客,所以需要維護一個顧客物件,後期通過getter方法獲取該訂單的所屬者。 |
對映關係上: |
|
主方: customer.hbm.xml <set name="orders"> <key column="c_id"></key> <one-to-many class="Order"/> </set> |
從方:order.hbm.xml <many-to-one name="customer" class="Customer" column="c_id" > |
注意: 在對映檔案中,雙方都維護了外來鍵。主方通過<set>集合中的<key>來維護,從方通過 <many-to-one> 中的column來維護。 |
第三種關係:如何去自動建立一個多對多的關係資料表(以多個學生選擇多門課程為例):
1、在Bean類中的表現:
在各自類中互相儲存著對方一個集合類的空物件,而不是引用,一定要初始化。因為當下次有個學生要選課了,此時課程集合沒有new操作,就直接呼叫集合的add方法,自然就丟擲空指標異常,但是如果new操作得到一個空集合物件,下次只要有學生選課了,直接呼叫add方法就會把課程這個物件加入到集合中去。
Student類:
package com.mikyou.day05.many2many;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Integer age;
private Set<Course> courses=new HashSet<Course>();
public Student(Long id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Student() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
Course類:
package com.mikyou.day05.many2many;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Course implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Set<Student> students=new HashSet<Student>();
private Integer credit;
public Course() {
super();
}
public Course(Long id, String name, Integer credit) {
super();
this.id = id;
this.name = name;
this.credit = credit;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
public Integer getCredit() {
return credit;
}
public void setCredit(Integer credit) {
this.credit = credit;
}
@Override
public String toString() {
return "Course [id=" + id + ", name=" + name + ", credit=" + credit + "]";
}
}
2、在對映關係中的表現:
student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.many2many">
<class name="Student" table="tbl_student">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<property name="age" />
<set name="courses" table="tbl_student_course">
<key column="s_id"></key><!--tbl_student_course表中的外來鍵s_id參考著本表的tbl_student中的主鍵id -->
<many-to-many class="Course" column="c_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
course.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.many2many">
<class name="Course" table="tbl_course">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<!-- 配置多對多 -->
<set name="students" table="tbl_student_course">
<key column="c_id"></key><!--tbl_student_course表中的外來鍵c_id參考著本表的tbl_course中的主鍵id -->
<many-to-many class="Student" column="s_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
對映多對多關聯
資料庫表中的關係:一個學生選擇多門課程,一門課程也可以有很多學生來選擇 |
||
主表:d_student( Id name age ); |
從表: d_course( Id name ); |
|
橋表:d_student_course( student_id references d_student(id), course_id references d_course(id). unique(student_id,course_id) ); 多對多的關係是維護在橋表上的,橋表中維護了兩個外來鍵,分別指向兩個表的主鍵,並且這兩個外來鍵為聯合主鍵。 |
||
類中的關係: 雙向維護 |
||
主類 Student{ Id name age Set<User> courses= new HashSet<>() } 一個學生對應多門課程,用一個集合來維護 |
從類:Course{ Id name Set<Student> students=new hashSet<>() } 一個門課程對應多個學生,需要用一個集合來維護 |
|
對映關係上: |
||
主方:student.hbm.xm l<set name="courses" table="tbl_student_course"> <key column="s_id"></key> <many-to-manyclass="Course" column="c_id"></many-to-many> </set> |
從方:course.hbm.xml <set name="students" table="tbl_student_course"> <key column="c_id"></key> <many-to-many class="Student" column="s_id"></many-to-many> </set> |
|
注意: 在對映元素上反應的是關聯關係,由於多對多需要使用橋表來維護關聯關係,所以需要在set元素中新增table元素用來指定橋表,key元素中的column屬性表示本類在橋表中的外來鍵。many-to-many表示對應的另外一方,其中的column屬性表示對應的類在橋表中的外來鍵。 |
第三種關係:多對多關係中的另一種常用形式:將一個多對多形式問題分解成兩個一對多的形式的問題
這種轉換後的好處就是我們控制橋表字段,也就是說我可以任意定製橋表;因為如果使用的是上一種方式的處理的話,橋表是系統自動產生的,並且這樣的橋表只能有兩個欄位分別是兩個表的主鍵,也就是橋表的兩個外來鍵。通常這樣的橋表不能滿足現實需求的,就比如上面的學生選課來說,就會自動產生一個選課關係表,現實需求中通常會在選課關係中新增一個分數或者老師評語,也就是某某選了某門課成績多少,老師評語是什麼?這樣的一個需求很常見,但是如果使用系統自動產生通過many-to-many方式來生成表的話是無法滿足現實需求,所以就出現這種將一個多對多的形式轉換成兩個一對多的形式的問題。這樣的操作就需要我們自己手動的去建立橋表。學生選課關係就變成了:一個學生對應多種選課關係,一門課程對應多種選課關係。
1、在Bean類中的表現:
我們這裡需要三個Bean類:一個是Student類,一個是Course類,另一個就是StuCou類(選課關係類)
在Student類中儲存著一個Set<StuCou>集合,有多個選課關係,在Course類中也儲存一個Set<StuCou>集合,有多個選課關係。在StuCou類中的分別儲存著Student和Course的引用。
Student類:
package com.mikyou.day05.double_one2many;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Integer age;
private Set<StuCou> stuCous=new HashSet<StuCou>();//儲存著多個選課關係
public Student(Long id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Student() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Set<StuCou> getStuCous() {
return stuCous;
}
public void setStuCous(Set<StuCou> stuCous) {
this.stuCous = stuCous;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
Course類:
package com.mikyou.day05.double_one2many;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Course implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Set<StuCou> stuCous=new HashSet<StuCou>();//儲存著多個選課關係
private Integer credit;
public Course() {
super();
}
public Course(Long id, String name, Integer credit) {
super();
this.id = id;
this.name = name;
this.credit = credit;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<StuCou> getStuCous() {
return stuCous;
}
public void setStuCous(Set<StuCou> stuCous) {
this.stuCous = stuCous;
}
public Integer getCredit() {
return credit;
}
public void setCredit(Integer credit) {
this.credit = credit;
}
@Override
public String toString() {
return "Course [id=" + id + ", name=" + name + ", credit=" + credit + "]";
}
}
StuCou類:
package com.mikyou.day05.double_one2many;
//學生選課關係,抽取一個選課關係,讓原來的一個多對多的關係直接轉換成兩個一對多的關係
public class StuCou {
private Long id;
private Double grade;//新增擴充套件屬性grade分數
private String comment;//新增擴充套件屬性comment評語
//
private Student student;
private Course course;
public StuCou(Long id, Double grade, String comment) {
super();
this.id = id;
this.grade = grade;
this.comment = comment;
}
public StuCou() {
// TODO Auto-generated constructor stub
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Double getGrade() {
return grade;
}
public void setGrade(Double grade) {
this.grade = grade;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
}
2、在對映檔案中的表現:
在對映檔案配置實際上和一對多配置是一樣的,只不過這裡是配置兩個一對多的關係,就是需要在橋表StuCou中的配置兩個<many-to-one>
student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.double_one2many">
<class name="Student" table="tbl_student">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<property name="age" />
<set name="stuCous">
<key column="s_id"></key><!--tbl_student_course表中的外來鍵s_id參考著本表的tbl_student中的主鍵id -->
<one-to-many class="StuCou" />
</set>
</class>
</hibernate-mapping>
course.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.double_one2many">
<class name="Course" table="tbl_course">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="name" />
<property name="credit" />
<!-- 配置多對多 -->
<set name="stuCous">
<key column="c_id"></key><!--tbl_student_course表中的外來鍵c_id參考著本表的tbl_course中的主鍵id -->
<one-to-many class="StuCou" />
</set>
</class>
</hibernate-mapping>
橋表對映檔案stucou.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mikyou.day05.double_one2many">
<class name="StuCou" table="tbl_student_course">
<id name="id" column="id">
<generator class="increment" />
</id>
<property name="grade" />
<property name="comment" />
<!-- 配置多對多 -->
<many-to-one name="student" class="Student" column="s_id"></many-to-one>
<many-to-one name="course" class="Course" column="c_id"></many-to-one>
</class>
</hibernate-mapping>
注意:實際上這種方式在現實需求用的更多一些,所以這種情況使用就是當你的橋表中需要新增適應需求的屬性這時候就需要考慮將一個多對多的關係轉換成兩個一對多的關係第四種關係:如何去自動建立一個具有繼承關係資料表(基類:Animal 兩個子類:Dog、Bird)
所謂繼承對映實際上對應著就是面向物件中的繼承機制,這種繼承關係對映在現實需求其實用處也蠻大的:就比如說我們設想一個需求,在一個專案中或者多個專案的我們可能多次都需要用到上傳附件或者上傳圖片的功能,實際上這操作是和專案沒有多大關係,可以說它是通用的。那既然這樣的話為什麼不能抽取一個這樣的操作單獨用一個表處理,然後需要使用這些操作的表只需要繼承這個基類表不就行了嗎?這樣就大大重構了我們的專案程式碼。
1、在Bean類中的表現:
先寫一個Animal類,然後寫一個Dog類和一個Bird類分別都去繼承這個Animal類
Animal
package com.mikyou.day05.inherit;
import java.io.Serializable;
public class Animal implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Animal(Long id, String name) {
super();
this.id = id;
this.name = name;
}
public Animal() {
super();
}
@Override
public String toString() {
return "Animal [id=" + id + ", name=" + name + "]";
}
}
Dog類:
package com.mikyou.day05.inherit;
public class Dog extends Animal{
/**
*
*/
private static final long serialVersionUID = 1L;
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Dog [color=" + color + "]";
}
}
Bird類:
package com.mikyou.day05.inherit;
public class Bird extends Animal{
/**
*
*/
private static final long serialVersionUID = 1L;
private String type;//品種
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
對映檔案:
對映檔案生成表有兩種:一種是將所有的子父類放在一張表中,另一種就是一個類就是一張表(個人認為這種方式更好)
第一種是將所有的子父類放在一張表中:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.briup.day5.inherit">
<class name="Animal" table="tbl_animal">
<id name="id" column="id">
<generator class="uuid.hex"/>
</id>
<property name="name"/>
<joined-subclass name="Dog" table="tbl_dog">
<key column="id"/>
<property name="color"/>
</joined-subclass>
<joined-subclass name="Bird" table="tbl_bird">
<key column="id"/>
<property name="type"/>
</joined-subclass>
</class>
</hibernate-mapping>
第二種就是一個類就是一張表:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.briup.day5.inherit">
<class name="Animal" abstract="true">
<id name="id" column="id">
<generator class="uuid.hex"/>
</id>
<property name="name"/>
<union-subclass name="Dog" table="tbl_dog">
<property name="color"/>
</union-subclass>
<union-subclass name="Bird" table="tbl_bird">
<property name="type"/>
</union-subclass>
</class>
</hibernate-mapping>
繼承對映
1每個類一張表
在表中的關係--子類的主鍵引用父類的主鍵,保證父子類的id一致 |
||
父類表--動物 animal( id, name ); |
子類表---狗 Dog( id references animal(id), type ); |
子類表---鳥 Bird( id references animal(id), type ); |
在類中的關係 |
||
Animal{ id, name } |
Dog extends Animal{ type } |
Bird extends Animal{ color } |
在對映檔案中的關係,配置在同一個對映檔案中 |
||
<class name="Animal" table="d_animal"> <id name="id" column="id"> <generator class="increment"/> </id> <property name="name"/> <!-- 以上是配置父類的基本屬性,需要指定父類使用的表名--> <!-- 以上是配置子類的配置,需要指定子類使用的表名,使用joined-subclass來和父類關聯,key值繼承父類的,column指定子類在表中的主鍵;property為子類特有的屬性--> <joined-subclass name="Dog" table="h_dog"> <key column="id"></key> <property name="type"/> </joined-subclass> <joined-subclass name="Bird" table="h_bird"> <key column="id"></key> <property name="color"></property> </joined-subclass> </class> |
2一個類域一張表
在表中的關係--父子類共用一張表,這張表中包含了父子類的所有欄位 |
||
Allclass( id name type color a_value --用來表示該條記錄是屬於哪個類的 ); |
||
在類中的關係 |
||
Animal{ id, name } |
Dog extends Animal{ type } |
Bird extends Animal{ color } |
在對映檔案中的關係,配置在同一個對映檔案中 |
||
<class name="Animal" table="h_allclass"> <id name="id" column="id"> <generator class="increment"> </generator> </id> <!-- discriminator用來指定標識列 --> <discriminator column="a_value"/> <property name="name"/> <!-- discriminator-value用來指定標識列中應該填入的值,用這個值來區分這條記錄是屬於哪個類的,property用來指明子類特有的屬性 --> <subclass name="Dog" discriminator-value="dog"> <property name="type"/> </subclass> <subclass name="Bird" discriminator-value="bird"> <property name="color"/> </subclass> </class> |
3每個子類一張表
在表中的關係--父子類共用一張表,這張表中包含了父子類的所有欄位 |
||
在類中的關係 |
||
Animal{ id, name } |
Dog extends Animal{ type } |
Bird extends Animal{ color } |
在對映檔案中的關係,配置在同一個對映檔案中 |
||
<class name="Animal"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <property name="color"/> <union-subclass name="Dog" table="dog"> <property name="callType"></property> </union-subclass> <union-subclass name="Bird" table="bird"> <property name="type"></property> </union-subclass> </class> |
||
主鍵生成方式不能使用Increment,因為Animal類並沒有對應的表,可以使用序列 |
到這裡Hibernate中表的對映關係就講這麼多了。