Hibernate联合主键映射
Hibernate允许直接将实体类的多个属性映射成联合主键,如果需要直接将实体类的多列映射成联合主键,则该实体类必须满足如下条件:
i. 有无参的构造方法
ii. 实现Java.io.Serializable接口
iii. 建议根据联合主键列所映射的属性来重写equals()和hashCode()方法
例:
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name="teacher")
public class Teacher implements Serializable{
private static final long serialVersionUID = 4938691487727505015L;
private int id;
private String name;
private Title title;
private Date date;
@Id //!!
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Id //!!
@Column(length=50)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Enumerated(EnumType.STRING)
public Title getTitle() {
return title;
}
public void setTitle(Title title) {
this.title = title;
}
@Temporal(TemporalType.DATE)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
//重写equals()方法,根据id, name进行判断
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj instanceof TeacherPk) {
TeacherPk pk = (TeacherPk) obj;
if(this.id == pk.getId() && this.name.equals(pk.getName())) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
return this.getName().hashCode();
}
}
测试方法:
@Test
public void Teacher() {
Teacher teacher = new Teacher();
teacher.setId(1);
teacher.setName("teacher");
teacher.setTitle(Title.A);
teacher.setDate(new Date());
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(teacher);
transaction.commit();
session.close();
HibernateUtil.close();
}
控制台日志
尝试插入相同的记录
传统方式
如果使用传统方式来开发Hibernate实体类,则实体类的设计不同于单一主键时:要将属于联合主键的字段从实体类中分离,单独建立一个主键类,这个主键类要求拥有无参的构造方法、实现**Java.io.Serializable**接口和重写**equals()**和**hashCode()**方法,因为数据库是要根据不同的字段的值判断是否为唯一主键的,那么判断机制肯定不能够和以往基于单一主键的判断机制相同。
实体类
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int 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;
}
}
XML方式:
现在要改造为联合主键(id和name字段)
首先将id和name分离出去,建立主键类
//主键类
import java.io.Serializable;
public class StudentPk implements Serializable{
private static final long serialVersionUID = 8538253779495022662L;
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj instanceof StudentPk) {
StudentPk pk = (StudentPk) obj;
if(this.id == pk.getId() && this.name.equals(pk.getName())) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
新的实体类
public class Student {
private StudentPk pk = null;
private int age;
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;
}
}
student.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="pers.msidolphin.hibernate.domain">
<class name="Student" table="_STUDENT">
<!--这个name属性指定的是主键对象在实体类中的属性名 class当然是主键类对应的完整类名-->
<composite-id name="pk" class="pers.msidolphin.hibernate.domain.StudentPk">
<!--映射联合主键里的各个属性-->
<key-property name="id" column="ID"></key-property>
<key-property name="name" column="NAME" length="50"></key-property>
</composite-id>
<property name="age" column="AGE"/>
</class>
</hibernate-mapping>
测试方法:
@Test
public void Student() {
Student stu = new Student();
StudentPk pk = new StudentPk();
pk.setId(1);
pk.setName("admin");
stu.setAge(21);
stu.setPk(pk);
Configuration cfg = new Configuration();
cfg = cfg.configure();
SessionFactory sf = HibernateUtil.getSessionFactory();
Session session = sf.openSession();
Transaction transaction = session.beginTransaction();
session.save(stu);
transaction.commit();
session.close();
sf.close();
}
控制台日志打印出的建表语句,primary key(id, name)说明以id和name字段建立了联合主键
查看插入结果:
尝试插入相同的记录
注解(Annotation)方式:
有三种:
i. **@Embeddable**:将主键类注解为@Embeddable,并将实体类的主键类对象属性加上@Id注解
ii. **@EmbeddedId**:直接把实体类的主键类对象属性加上此注解
iii. **@IdClass**:在实体类加上@IdClass注解,并且将该实体类中所有属于主键的属性都注解为@Id(这种方式在实体类中保留了主键字段,但是还是要依赖主键类)
@Embeddable方式:
实体类:
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name="teacher1")
public class Teacher {
private TeacherPk pk = null;
private Title title;
private Date date;
@Id //!!
public TeacherPk getPk() {
return pk;
}
public void setPk(TeacherPk pk) {
this.pk = pk;
}
@Enumerated(EnumType.STRING)
public Title getTitle() {
return title;
}
public void setTitle(Title title) {
this.title = title;
}
@Temporal(TemporalType.DATE)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
主键类:
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable //!!
public class TeacherPk implements Serializable{
private static final long serialVersionUID = 1084438907442149399L;
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(length=50)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj instanceof TeacherPk) {
TeacherPk pk = (TeacherPk) obj;
if(this.id == pk.getId() && this.name.equals(pk.getName())) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
测试结果:
@EmbeddedId方式:
实体类:
import java.util.Date;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Table(name="teacher2")
public class Teacher2 {
private TeacherPk2 pk = null;
private Title title;
private Date date;
@EmbeddedId //!!
public TeacherPk2 getPk() {
return pk;
}
public void setPk(TeacherPk2 pk) {
this.pk = pk;
}
@Enumerated(EnumType.STRING)
public Title getTitle() {
return title;
}
public void setTitle(Title title) {
this.title = title;
}
@Temporal(TemporalType.DATE)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
主键类:
import java.io.Serializable;
import javax.persistence.Column;
public class TeacherPk2 implements Serializable{
private static final long serialVersionUID = 1084438907442149399L;
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(length=50)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj instanceof TeacherPk2) {
TeacherPk2 pk = (TeacherPk2) obj;
if(this.id == pk.getId() && this.name.equals(pk.getName())) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
测试结果:
@IdClass方式:
实体类:
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity()
@Table(name="teacher3")
@IdClass(TeacherPk3.class) //!!
public class Teacher3 {
private int id;
private String name;
private Title title;
private Date date;
@Id //!!
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Id //!!
@Column(length=50)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Enumerated(EnumType.STRING)
public Title getTitle() {
return title;
}
public void setTitle(Title title) {
this.title = title;
}
@Temporal(TemporalType.DATE)
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
主键类: