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();
	}

}
测试系果为:

hibernate的联合主键_第1张图片

上述异常是因为没有将主键生成类进行序列化导致的




上面虽然运行了,但是有警告,是提醒要将主键生成类的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();
	}

}

测试结果为:

hibernate的联合主键_第2张图片

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;
	}
	
}
运行结果:

hibernate的联合主键_第3张图片

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();
    }

}

运行结果:

hibernate的联合主键_第4张图片

以上即为联合主键的内容,需要指明的是在实际的使用过程中,annotation中多使用@EmbeddedId或者@IdClass@Id。




你可能感兴趣的:(Hibernate,annotation,id,联合主键)