hibernate的聯合主鍵

不管是xml方式還是annotation方式的聯合主鍵都需要使用到一個額外的主鍵生成類,這個類必須是序列化的,即需要implements Serializable,另外,需要重寫equals和hashCode方法,以保證數據正常傳輸和主鍵的唯一性。

1.新建主鍵生成類StudentPK

package com.baosight.model;

import java.io.Serializable;

/**
 * <p>Title:StudentPK </p>
 * <p>Description:TODO </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-15 下午8:08:16*/
public class StudentPK implements Serializable{
private String id;
private String name;
public String getId() {
	return id;
}
public void setId(String id) {
	this.id = id;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
	@Override
	public boolean equals(Object obj) {
		// TODO Auto-generated method stub
		if(obj instanceof StudentPK){
			StudentPK pk = (StudentPK)obj;
			if(this.id.equals(pk.getId())&&this.name.equals(pk.getName())){
				return true;
			}
		}
		return false;
	}
		@Override
		public int hashCode() {
			// TODO Auto-generated method stub
			return this.id.hashCode();
		}
}

2.使用xml方式的聯合主鍵

在Student中引用StudentPK

package com.baosight.model;

/**
 * <p>Title: </p>
 * <p>Description:Student </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-10 下午12:32:46*/
public class Student {
//	private String id;
//	private String name;
	private StudentPK pk;
	private int age;
//	public String getId() {
//		return id;
//	}
//	public void setId(String id) {
//		this.id = id;
//	}
//	public String getName() {
//		return name;
//	}
//	public void setName(String name) {
//		this.name = name;
//	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public StudentPK getPk() {
		return pk;
	}
	public void setPk(StudentPK pk) {
		this.pk = pk;
	}
	
}
3.配置Student.hbm.xml,需要使用composite-id來定義聯合主鍵

<?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 package="com.baosight.model">
<class name="Student">
<!-- <id name="id" >
<generator class="uuid"></generator>
</id> -->
<composite-id name="pk" class="StudentPK">
<key-property name="id"></key-property>
<key-property name="name"></key-property>
</composite-id>
<!-- <property name="name"></property> -->
<property name="age"></property>
</class>
</hibernate-mapping>
其中,用name指明Student中聯合主鍵的名稱,用class指明主鍵生成類,使用key-property指明主鍵生成類中作爲聯合主鍵的屬性

4.使用HibernateIDTest進行JUnit測試

package com.baosight.model;

import static org.junit.Assert.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * <p>Title:HibernateIDTest </p>
 * <p>Description:TODO </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-14 下午9:11:00*/
public class HibernateIDTest {

	private static SessionFactory sf = null;
	@BeforeClass
	public static void beforeClass(){
		// 讀取配置文件
		Configuration cfg = new AnnotationConfiguration();
		// 得到session工廠
		sf = cfg.configure().buildSessionFactory();
	}
	@Test
	public void testStudent() {
		// 學生測試類
		Student s = new Student();
		StudentPK pk = new StudentPK();
		pk.setId("1");
		pk.setName("zhangsan");
		s.setPk(pk);
//		s.setName("s1");
		s.setAge(20);

		// 得到session
		Session session = sf.openSession();
		// 開啓事務
		session.beginTransaction();
		// session執行save
		session.save(s);
		// 事務提交
		session.getTransaction().commit();
		// 關閉session
		session.close();
	}
	@Test
	public void testTeacher() {
		// 教師測試類
		Teacher t = new Teacher();
//		TeacherPK pk = new TeacherPK();
//		pk.setId("1");
//		pk.setName("t1");
//		t.setPk(pk);
		t.setId("1");
		t.setName("t1");
		t.setTitle("中級");


		// 得到session
		Session session = sf.openSession();
		// 開啓事務
		session.beginTransaction();
		// session執行save
		session.save(t);
		// 事務提交
		session.getTransaction().commit();
		// 關閉session
		session.close();
	}
	@AfterClass
	public static void afterClass(){
		// 關閉session工廠
		sf.close();
	}

}
測試系果爲:



上述異常是因爲沒有將主鍵生成類進行序列化導致的




上面雖然運行了,但是有警告,是提醒要將主鍵生成類的equals和hashCode方法進行重寫


5.hibernate的annotation形式的聯合主鍵

先看下API文檔

2.2.6. 映射覆合主鍵與外鍵

組合主鍵使用一個可嵌入的類作爲主鍵表示,因此你需要使用@Id 和@Embeddable兩個註解. 還有一種方式是使用@EmbeddedId註解.注意所依賴的類必須實現 serializable以及實現equals()/hashCode()方法. 你也可以如Mapping identifier properties一章中描述的辦法使用@IdClass註解.

@Entity
public class RegionalArticle implements Serializable {

    @Id
    public RegionalArticlePk getPk() { ... }
}

@Embeddable
public class RegionalArticlePk implements Serializable { ... }
         

或者

@Entity
public class RegionalArticle implements Serializable {

    @EmbeddedId
    public RegionalArticlePk getPk() { ... }
}

public class RegionalArticlePk implements Serializable { ... }
         
Mapping identifier properties一章中描述如下:

下面是定義組合主鍵的幾種語法:

  • 將組件類註解爲@Embeddable,並將組件的屬性註解爲@Id
  • 將組件的屬性註解爲@EmbeddedId
  • 將類註解爲@IdClass,並將該實體中所有屬於主鍵的屬性都註解爲@Id

對於EJB2的開發人員來說 @IdClass是很常見的, 但是對於Hibernate的用戶來說就是一個嶄新的用法. 組合主鍵類對應了一個實體類中的多個字段或屬性, 而且主鍵類中用於定義主鍵的字段或屬性和 實體類中對應的字段或屬性在類型上必須一致.下面我們看一個例子:

@Entity
@IdClass(FootballerPk.class)
public class Footballer {
    //part of the id key
    @Id public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    //part of the id key
    @Id public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getClub() {
        return club;
    }

    public void setClub(String club) {
        this.club = club;
    }

    //appropriate equals() and hashCode() implementation
}

@Embeddable
public class FootballerPk implements Serializable {
    //same name and type as in Footballer
    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    //same name and type as in Footballer
    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    //appropriate equals() and hashCode() implementation
}

如上, @IdClass指向對應的主鍵類.

綜上所述共有3中方式:

一是使用@Embeddable@Id

二是使用@EmbeddedId

三是使用@IdClass@Id

6.使用@Embeddable@Id,即將組件類註解爲@Embeddable,並將組件的屬性註解爲@Id

新建主鍵生成類TeacherPK

package com.baosight.model;

import java.io.Serializable;

import javax.persistence.Embeddable;

/**
 * 聯合主鍵類
* <p>Title:TeacherPK </p>
* <p>Description:TODO </p>
* <p>Company: </p> 
* @author yuan 
* @date 2016-4-15 下午9:01:00
 */
@Embeddable
public class TeacherPK implements Serializable{
private String id;
private String name;
public String getId() {
	return id;
}
public void setId(String id) {
	this.id = id;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
@Override
public boolean equals(Object obj) {
	// TODO Auto-generated method stub
	if(obj instanceof StudentPK){
		StudentPK pk = (StudentPK)obj;
		if(this.id.equals(pk.getId())&&this.name.equals(pk.getName())){
			return true;
		}
	}
	return false;
}
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return this.id.hashCode();
	}	
}

在Teacher中引用TeacherPK

package com.baosight.model;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.SequenceGenerator;
import javax.persistence.TableGenerator;

/**
 * <p>Title: </p>
 * <p>Description:Teacher </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-10 下午12:32:46*/
@Entity
@TableGenerator(name="tableGEN",table="table_gen",pkColumnName="pk_key",valueColumnName="pk_value",pkColumnValue="teacher",allocationSize=1)
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
@IdClass(value=TeacherPK.class)
public class Teacher {
//	private String id;
//	private String name;
	private String title;
	private TeacherPK pk;
//	@Id
//	@GeneratedValue//auto
//	@GeneratedValue(strategy=GenerationType.TABLE,generator="tableGEN")
//	@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
	/*public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	@Id
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}*/
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
//	@EmbeddedId
	@Id
	public TeacherPK getPk() {
		return pk;
	}
	public void setPk(TeacherPK pk) {
		this.pk = pk;
	}
	
}


使用JUnit進行單元測試

package com.baosight.model;

import static org.junit.Assert.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * <p>Title:HibernateIDTest </p>
 * <p>Description:TODO </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-14 下午9:11:00*/
public class HibernateIDTest {

	private static SessionFactory sf = null;
	@BeforeClass
	public static void beforeClass(){
		// 讀取配置文件
		Configuration cfg = new AnnotationConfiguration();
		// 得到session工廠
		sf = cfg.configure().buildSessionFactory();
	}
	@Test
	public void testStudent() {
		// 學生測試類
		Student s = new Student();
		StudentPK pk = new StudentPK();
		pk.setId("1");
		pk.setName("zhangsan");
		s.setPk(pk);
//		s.setName("s1");
		s.setAge(20);

		// 得到session
		Session session = sf.openSession();
		// 開啓事務
		session.beginTransaction();
		// session執行save
		session.save(s);
		// 事務提交
		session.getTransaction().commit();
		// 關閉session
		session.close();
	}
	@Test
	public void testTeacher() {
		// 教師測試類
		Teacher t = new Teacher();
		TeacherPK pk = new TeacherPK();
		pk.setId("1");
		pk.setName("t1");
		t.setPk(pk);
//		t.setId("1");
//		t.setName("t1");
		t.setTitle("中級");


		// 得到session
		Session session = sf.openSession();
		// 開啓事務
		session.beginTransaction();
		// session執行save
		session.save(t);
		// 事務提交
		session.getTransaction().commit();
		// 關閉session
		session.close();
	}
	@AfterClass
	public static void afterClass(){
		// 關閉session工廠
		sf.close();
	}

}

測試結果爲:

7.使用@EmbeddedId,即將組件的屬性註解爲@EmbeddedId

TeacherPK類不需要使用註解

Teacher類如下:

package com.baosight.model;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.SequenceGenerator;
import javax.persistence.TableGenerator;

/**
 * <p>Title: </p>
 * <p>Description:Teacher </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-10 下午12:32:46*/
@Entity
@TableGenerator(name="tableGEN",table="table_gen",pkColumnName="pk_key",valueColumnName="pk_value",pkColumnValue="teacher",allocationSize=1)
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
@IdClass(value=TeacherPK.class)
public class Teacher {
//	private String id;
//	private String name;
	private String title;
	private TeacherPK pk;
//	@Id
//	@GeneratedValue//auto
//	@GeneratedValue(strategy=GenerationType.TABLE,generator="tableGEN")
//	@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
	/*public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	@Id
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}*/
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	@EmbeddedId
//	@Id
	public TeacherPK getPk() {
		return pk;
	}
	public void setPk(TeacherPK pk) {
		this.pk = pk;
	}
	
}
運行結果:



8.使用@IdClass和@Id,即將類註解爲@IdClass,並將該實體中所有屬於主鍵的屬性都註解爲@Id

注意此時Teacher使用自己的屬性註解爲@Id,使用@IdClass指明主鍵生成類

Teacher如下:

package com.baosight.model;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.SequenceGenerator;
import javax.persistence.TableGenerator;

/**
 * <p>Title: </p>
 * <p>Description:Teacher </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-10 下午12:32:46*/
@Entity
@TableGenerator(name="tableGEN",table="table_gen",pkColumnName="pk_key",valueColumnName="pk_value",pkColumnValue="teacher",allocationSize=1)
@SequenceGenerator(name="teacherSEQ",sequenceName="teacherSEQ_DB")
@IdClass(value=TeacherPK.class)
public class Teacher {
    private String id;
    private String name;
    private String title;
//    private TeacherPK pk;
    @Id
//    @GeneratedValue//auto
    @GeneratedValue(strategy=GenerationType.TABLE,generator="tableGEN")
//    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="teacherSEQ")
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    @Id
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
/*//    @EmbeddedId
    public TeacherPK getPk() {
        return pk;
    }
    public void setPk(TeacherPK pk) {
        this.pk = pk;
    }*/

}
JUnit測試類如下:

package com.baosight.model;

import static org.junit.Assert.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * <p>Title:HibernateIDTest </p>
 * <p>Description:TODO </p>
 * <p>Company: </p> 
 * @author yuan 
 * @date 2016-4-14 下午9:11:00*/
public class HibernateIDTest {

    private static SessionFactory sf = null;
    @BeforeClass
    public static void beforeClass(){
        // 讀取配置文件
        Configuration cfg = new AnnotationConfiguration();
        // 得到session工廠
        sf = cfg.configure().buildSessionFactory();
    }
    @Test
    public void testStudent() {
        // 學生測試類
        Student s = new Student();
        StudentPK pk = new StudentPK();
        pk.setId("1");
        pk.setName("zhangsan");
        s.setPk(pk);
//        s.setName("s1");
        s.setAge(20);

        // 得到session
        Session session = sf.openSession();
        // 開啓事務
        session.beginTransaction();
        // session執行save
        session.save(s);
        // 事務提交
        session.getTransaction().commit();
        // 關閉session
        session.close();
    }
    @Test
    public void testTeacher() {
        // 教師測試類
        Teacher t = new Teacher();
//        TeacherPK pk = new TeacherPK();
//        pk.setId("1");
//        pk.setName("t1");
//        t.setPk(pk);
        t.setId("1");
        t.setName("t1");
        t.setTitle("中級");


        // 得到session
        Session session = sf.openSession();
        // 開啓事務
        session.beginTransaction();
        // session執行save
        session.save(t);
        // 事務提交
        session.getTransaction().commit();
        // 關閉session
        session.close();
    }
    @AfterClass
    public static void afterClass(){
        // 關閉session工廠
        sf.close();
    }

}

運行結果:



以上即爲聯合主鍵的內容,需要指明的是在實際的使用過程中,annotation中多使用@EmbeddedId或者@IdClass@Id。




發佈了50 篇原創文章 · 獲贊 46 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章