10 15 Hibernate之複合主鍵映射

首先在開發之中複合主鍵是一中強烈不建議使用的技術,在任何一張數據表裏面如果要設置主鍵應該只設置一個字段,但是複合主鍵畢竟屬於標準的SQL語法,所以在Hibernate或者是JPA之中也都有複合主鍵的定義支持。
範例:數據庫腳本

-- 刪除數據表
DROP TABLE IF EXISTS member;
-- 創建數據表
CREATE TABLE member(
	mid VARCHAR(50),
	mname VARCHAR(50),
	mage INT,
	CONSTRAINT pk_mid_name PRIMARY KEY(mid,name)
);

此時設置了兩個主鍵,但是一定要記住一點,主鍵不應該重複,所以在隨後生成Hibernate操作的時候就要觀察它生成類的形式。

1 基於HBM文件的配置


範例:定義MemberId類

@SuppressWarnings("serial")
public class MemberId implements java.io.Serializable {

	// Fields

	private String mid;
	private String mname;
}

爲了能夠確定唯一,在這個MemberId類裏面必須要覆寫equals()和hashCode()兩個方法。
範例:在Member類裏面利用MemberId來描述複合主鍵

@SuppressWarnings("serial")
public class Member implements java.io.Serializable {

	// Fields

	private MemberId id;
	private Integer mage;
}

隨後需要觀察Member.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">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="org.lks.pojo.Member" table="member" catalog="hedb">
    	<!-- 取代的是id元素,表示此時的id是一個複合主鍵 -->
        <composite-id name="id" class="org.lks.pojo.MemberId">
            <key-property name="mid" type="java.lang.String">
                <column name="mid" length="50" />
            </key-property>
            <key-property name="mname" type="java.lang.String">
                <column name="mname" length="50" />
            </key-property>
        </composite-id>
        <property name="mage" type="java.lang.Integer">
            <column name="mage" />
        </property>
    </class>
</hibernate-mapping>

範例:測試代碼

package org.lks.test;

import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
import org.lks.pojo.MemberId;

public class TestMemberInsert {

	public static void main(String[] args) {
		MemberId id = new MemberId();
		id.setMid("3161301220");
		id.setMname("lks");
		Member vo = new Member();
		vo.setId(id);
		vo.setMage(23);
		HibernateSessionFactory.getSession().save(vo);
		HibernateSessionFactory.getSession().beginTransaction().commit();
		HibernateSessionFactory.closeSession();
		System.exit(0);
	}
}

Hibernate: 
    insert 
    into
        hedb.member
        (mage, mid, mname) 
    values
        (?, ?, ?)

此時信息可以正常保存(複合主鍵不重複)。

當然在進行數據查詢的時候也有一些需要注意的概念,既然ID不能夠重複,所以在數據查詢中使用的get()方法來講就必須考慮到複合主鍵不能重複的特點,所以才覆寫了hashCode()以及equals()方法。
範例:數據查詢

package org.lks.test;

import org.lks.dbc.HibernateSessionFactory;
import org.lks.pojo.Member;
import org.lks.pojo.MemberId;

public class TestMemberGet {

	public static void main(String[] args) {
		MemberId id = new MemberId();
		id.setMid("3161301220");
		id.setMname("lks");
		Member vo = (Member)HibernateSessionFactory.getSession().get(Member.class, id);
		System.out.println(vo);
		HibernateSessionFactory.closeSession();
		System.exit(0);
	}
}

Hibernate: 
    select
        member0_.mid as mid1_0_0_,
        member0_.mname as mname2_0_0_,
        member0_.mage as mage3_0_0_ 
    from
        hedb.member member0_ 
    where
        member0_.mid=? 
        and member0_.mname=?
org.lks.pojo.Member@3d7fa3ae

所有的類的屬性都會自動的根據配置進行不同類型的關係組成。

2 Annotation配置

雖然複合主鍵出現較少,但是在JPA的開發標準中依然支持了複合主鍵映射,並且這個複合主鍵的映射與之前的細粒度劃分不同,它可以完美的配置。
範例:觀察生成的MemberId程序類

package org.lks.pojo;

import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
 * MemberId entity. @author MyEclipse Persistence Tools
 */
@SuppressWarnings("serial")
@Embeddable

public class MemberId implements java.io.Serializable {

	// Fields

	private String mid;
	private String mname;

	// Constructors

	/** default constructor */
	public MemberId() {
	}

	/** full constructor */
	public MemberId(String mid, String mname) {
		this.mid = mid;
		this.mname = mname;
	}

	// Property accessors

	@Column(name = "mid", nullable = false, length = 50)

	public String getMid() {
		return this.mid;
	}

	public void setMid(String mid) {
		this.mid = mid;
	}

	@Column(name = "mname", nullable = false, length = 50)

	public String getMname() {
		return this.mname;
	}

	public void setMname(String mname) {
		this.mname = mname;
	}

	public boolean equals(Object other) {
		if ((this == other))
			return true;
		if ((other == null))
			return false;
		if (!(other instanceof MemberId))
			return false;
		MemberId castOther = (MemberId) other;

		return ((this.getMid() == castOther.getMid())
				|| (this.getMid() != null && castOther.getMid() != null && this.getMid().equals(castOther.getMid())))
				&& ((this.getMname() == castOther.getMname()) || (this.getMname() != null
						&& castOther.getMname() != null && this.getMname().equals(castOther.getMname())));
	}

	public int hashCode() {
		int result = 17;

		result = 37 * result + (getMid() == null ? 0 : this.getMid().hashCode());
		result = 37 * result + (getMname() == null ? 0 : this.getMname().hashCode());
		return result;
	}

}

範例:觀察Member.java類

package org.lks.pojo;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
 * Member entity. @author MyEclipse Persistence Tools
 */
@SuppressWarnings("serial")
@Entity
@Table(name = "member", catalog = "hedb")

public class Member implements java.io.Serializable {

	// Fields

	private MemberId id;
	private Integer mage;

	// Constructors

	/** default constructor */
	public Member() {
	}

	/** minimal constructor */
	public Member(MemberId id) {
		this.id = id;
	}

	/** full constructor */
	public Member(MemberId id, Integer mage) {
		this.id = id;
		this.mage = mage;
	}

	// Property accessors
	@EmbeddedId

	@AttributeOverrides({
			@AttributeOverride(name = "mid", column = @Column(name = "mid", nullable = false, length = 50)),
			@AttributeOverride(name = "mname", column = @Column(name = "mname", nullable = false, length = 50)) })

	public MemberId getId() {
		return this.id;
	}

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

	@Column(name = "mage")

	public Integer getMage() {
		return this.mage;
	}

	public void setMage(Integer mage) {
		this.mage = mage;
	}

}

由於有開發工具的支持,使用複合主鍵比較方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章