1. 程式人生 > >Hibernate 學習經驗之談-(四)關聯對映

Hibernate 學習經驗之談-(四)關聯對映

摘要:

(待編寫)

        Hibernate 是一個ORM 框架,它的重點就是物件之間的關係模型,維護物件之間的關係是hibernate 的核心內容,也是這個框架中相對比較難的一點。如果能夠靈活地運用好這個框架,必須熟悉物件之間的聯絡。Hibernate 中的主要有三種物件的關係:One to One(一對一關聯對映);One to Many (一對多關聯對映);Many to Many (關聯對映)。 每一種對映又分單向和雙向。在資料庫中關係表之間的關係只有一種,就是外來鍵關聯,hibernatre的物件對映就是建立在資料庫外來鍵關聯之上。

要掌握hibernate的關聯對映,必須要分析hibernate 在使用物件關聯時生成的DDL語句,理解每一種對映在資料庫中的對應處理方式。

單向關聯與雙向關聯的區別

    物件通過組合的方式來表達的類之間的關係,並在hbm檔案或者註解上做出明確的說明。 

           單向可以理解為在兩個有關聯的物件實體中,只在一方中說明關聯關係,物件只能在一方導向到另一方。

           雙向可以理解為在兩個有關聯的物件實體中,雙方都有說明關聯關係的配置,物件之間可以互相訪問到對方。

          導向的意思是說在物件的關聯欄位訪問到關聯的物件的資訊,雙向和單向在資料庫層級的實現基本一樣。

           對於設定了雙向關聯的實體,最好的做法就是在其中一方使用mappedBy 指定主導關係,不然會出現冗餘的資料欄位。原則是在1-1 可以任意設一方,1-N 在N方設定mappedBy,N-N 的在任意一方設定。mappedBy 是關聯註解的一個屬性,mappedBy="xxx",xxx 為主導關係的getXXX對應的值。例如mappedBy=“person”  person 對應的不是下文中的person 屬性,而是對應getter 中getXXX,的“XXX”位置的值,person 對應getPerson();

一.One to One(一對一關聯對映)

1.解析:

例如,一個人只能有一張身份證,一張身份證只能對應一個人;這兩個物件之間就是屬於一對一;一對一是三種關係中最簡單的一種。

2.種類:主鍵關聯,唯一外來鍵關聯;

2.1 主鍵關聯:兩個物件採用一樣的主鍵值來表明他們之間是屬於一對一的關係,這種方法是基本不用的。

2.2 外來鍵關聯:兩個物件採用外來鍵來表示兩個之間的聯絡。

3.配置方式(只講外來鍵關聯)

3.1單向配置

Person

package com.hwj.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;

@Table(name="t_person")
@Entity
@DynamicUpdate
public class Person {

	private int id;
	private String nickName;
	
	
	//關聯欄位
	private IDCard idCard;
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToOne
	public IDCard getIdCard() {
		return idCard;
	}
	public String getNickName() {
		return nickName;
	}	
	public void setId(int id) {
		this.id = id;
	}
	public void setIdCard(IDCard idCard) {
		this.idCard = idCard;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}

	
}

IDCard

<pre name="code" class="java">package com.hwj.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;

@Entity
@Table(name="t_idcard")
@DynamicUpdate
public class IDCard {

	private int id;
	private String name;
	private String idNo;

	
	
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	public String getIdNo() {
		return idNo;
	}
	public String getName() {
		return name;
	}

	public void setId(int id) {
		this.id = id;
	}
	public void setIdNo(String idNo) {
		this.idNo = idNo;
	}
	public void setName(String name) {
		this.name = name;
	}


	
}


hibernate 生成的sql語句
Hibernate: 
    create table t_idcard (
        id integer not null auto_increment,
        idNo varchar(255),
        name varchar(255),
        primary key (id)
    )
Hibernate: 
    create table t_person (
        id integer not null auto_increment,
        nickName varchar(255),
        idCard_id integer,
        primary key (id)
    )
Hibernate: 
    alter table t_person 
        add constraint FK_iwf0ex84epvoh2ndq1axpceg9 
        foreign key (idCard_id) 
        references t_idcard (id)

3.2 雙向配置

Person

package com.hwj.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;

@Table(name="t_person")
@Entity
@DynamicUpdate
public class Person {

	private int id;
	private String nickName;
	
	
	//關聯欄位
	private IDCard idCard;
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	
	@OneToOne(mappedBy="pserson")
	public IDCard getIdCard() {
		return idCard;
	}
	public String getNickName() {
		return nickName;
	}	
	public void setId(int id) {
		this.id = id;
	}
	public void setIdCard(IDCard idCard) {
		this.idCard = idCard;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}

	
}


IDCard

package com.hwj.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;

@Entity
@Table(name="t_idcard")
@DynamicUpdate
public class IDCard {

	private int id;
	private String name;
	private String idNo;
	private Person pserson;

	
	
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	public String getIdNo() {
		return idNo;
	}
	public String getName() {
		return name;
	}

	@OneToOne
	public Person getPserson() {
		return pserson;
	}
	public void setId(int id) {
		this.id = id;
	}
	public void setIdNo(String idNo) {
		this.idNo = idNo;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setPserson(Person pserson) {
		this.pserson = pserson;
	}


	
}


hibernate 生成的sql語句

Hibernate: 
    create table t_idcard (
        id integer not null auto_increment,
        idNo varchar(255),
        name varchar(255),
        pserson_id integer,
        primary key (id)
    )
Hibernate: 
    create table t_person (
        id integer not null auto_increment,
        nickName varchar(255),
        primary key (id)
    )
Hibernate: 
    alter table t_idcard 
        add constraint FK_pdvviqxfv7qwech66rqm08830 
        foreign key (pserson_id) 
        references t_person (id)


總結,使用主要使用外來鍵關聯,在雙方設定了雙向關聯的時候,進行mappedBy 設定。 

二.One to Many  與 Many to One

      其實一對多,還有多對一,都只是在不同的角度來看,但是對映產生的結果可能會不一樣。這裡使用Group 組與 User 成員來做舉例。

      1.單向對映

        1.1 One to Many (一對多 )

Group 對映

package com.hwj.model;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.UpdateTimestamp;

@Entity
@Table(name="t_group")
@DynamicUpdate
public class Group {

	private int id;
	private String name;
	private List<User> users;
	
	
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	
	
	
	@OneToMany
	@JoinColumn(name="group_id")
	public List<User> getUsers() {
		return users;
	}
	public void setId(int id) {
		this.id = id;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setUsers(List<User> users) {
		this.users = users;
	}
	
	
}


       User 的對映

package com.hwj.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;

@Entity
@Table(name="t_user")
@DynamicUpdate
public class User {

	private int id;
	private String name;	


	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}

	public String getName() {
		return name;
	}


	public void setId(int id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
	
	
}


產生的sql語句

Hibernate: 
    create table t_group (
        id integer not null auto_increment,
        name varchar(255),
        primary key (id)
    )
Hibernate: 
    create table t_user (
        id integer not null auto_increment,
        name varchar(255),
        group_id integer,
        primary key (id)
    )
Hibernate: 
    alter table t_user 
        add constraint FK_e5f24mh6aryt9hsy99oydps6g 
        foreign key (group_id) 
        references t_group (id)
注意,假如在一對多關聯對映中只使用了 One to Many 的話,hibernate 就會發生把One to Many 當成 many to many 方式生成sql 語句,生成的語句中會存在中間表。但是在關聯欄位新增@joinColumn(name="外來鍵名稱") ,j就可以避免這種情況生成正確的sql語句。

     1.2.many to one

          注:many to one 配置方式十分方便,只要在多的一方在關聯欄位加上 @ManyToOne 就可以正確在多一方生成外來鍵約束。

2.雙向關聯

注;雙向關聯中需要在one 的一方設定mappedBy ,在many to one 的一方沒有這個屬性。設定完後就是實現了對資料的雙向導航。

三.Many to Many (關聯對映)

1.單向對映

只要在關聯欄位上新增@ManyToMany 就可以實現多對多單向對映。

2.雙向對映

雙向對映的時候一定要設定在任意一方設定mappedBy 這樣才能不會執行重複的sql語句。

3.表生成

     多對多表對映是採用中間表的方式來實現對映的,中間表字段的修改可以使用@JoinTable來實現。這個註解可以修改中間表的表名,表中的外來鍵欄位。

            @JoinTable(

          joinColumns={@JoinColumn(name="本物件的外來鍵引用欄位名")},  //為陣列的原因是考慮到聯合主鍵的情況

         inverseJoinColumns={@JoinColumn(name="另外的一方的物件外來鍵引用的欄位名")}     //為陣列的原因是考慮到聯合主鍵的情況

         )