您的位置:首页 > 其它

hibernate 复合主键 注解

2017-02-16 00:19 260 查看
Hibernate注解规范的文档中提供了三种方法:

1. 将组件类注解为@Embeddable,并将组件的属性注解为@Id;

2. 将组件的属性注解为@Embeddable;


package com.cmh.beans;

import javax.persistence.Embeddable;
import java.io.Serializable;

@Embeddable
public class TestPK implements Serializable {

private static final long serialVersionUID = 7935499208104916305L;

private String firstName;

private String lastName;

public TestPK() {
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

@Override
public boolean equals(Object obj) {

if(this == obj) return true;
if(obj == null) return false;
if(!(obj instanceof TestKey)) return false;
TestPK objKey = (TestPK)obj;
if(firstName.equalsIgnoreCase(objKey.firstName) &&
lastName.equalsIgnoreCase(objKey.lastName)) {
return true;
}
return false;
}

@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + (firstName == null ? 0 : firstName.hashCode());
result = PRIME * result + (lastName == null ? 0 : lastName.hashCode());
return result;
}
}


主类

package com.cmh.beans;

import javax.persistence.Column;

import javax.persistence.EmbeddedId;

import javax.persistence.Entity;

import javax.persistence.Table;

/**

* Created by mianhai on 2017/2/16.

*/

@Entity

@Table

public class EmbeddableTest {

@EmbeddedId

private TestPK id;

private String name;

public EmbeddableTest() {
}

@Column(name = "firstname")
public String getFirstName(){
return id.getFirstName();
}

@Column(name = "lastname")
public String getLastName(){
return id.getLastName();
}

@Column(name = "name")
public String getName() {
return name;
}

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


}

这里需要注意的是在实体类中同时还要写上复合主键的字段比如@Column(name = “lastname”)和

@Column(name = “firstname”)

不想在TestPK中定义列名,可以用以下方法,用于公共复合主键

通过@AttributeOverride注释来指定Test类的firstName,lastName与数据库中表的first_name,last_name进行映射.

以下代码在class Test

@EmbeddedId

@AttributeOverrides( {

@AttributeOverride(name = firstName, column = @Column(name = first_name)),

@AttributeOverride(name = lastName, column = @Column(name = last_name)) })

将类注解为@IdClass,并将该实体中所有主键属性注解为@Id。

这里,我采用的是第三种方法——@IdClass,下面就是具体的代码,大家一块讨论一下。

首先,需要说明的是,采用@IdClass方式,需要根据所有的主键属性,建立一个主键类,该主键类包含所有的主键,而且,作为主键类,需要满足以下要求:

主键类必须实现序列化接口(implements Serializable);

主键类必须有默认的public无参数的构造方法;

主键类必须覆盖equals和hashCode方法。

代码如下:

我们的PK

package com.cmh.beans;

import java.io.Serializable;

/**
* Created by mianhai on 2017/2/15.
*/
public class TestKey implements Serializable{

private static final long serialVersionUID = 6811601262303871530L;

// 主键属性
private String ip;

// 主键属性
private String examPlaceId;

// 主键属性
private String examId;

/**
* 无参数的public构造方法,必须要有
*/
public TestKey() {

}

/**
* 重写了一个带参数的构造方法
* @param ip
* @param examPlaceId
* @param examId
*/
public TestKey(String ip, String examPlaceId, String examId) {
this.ip = ip;
this.examId = examId;
this.examPlaceId = examPlaceId;
}

public String getIp() {
return ip;
}

public void setIp(String ip) {
this.ip = ip;
}

public String getExamPlaceId() {
return examPlaceId;
}

public void setExamPlaceId(String examPlaceId) {
this.examPlaceId = examPlaceId;
}

public String getExamId() {
return examId;
}

public void setExamId(String examId) {
this.examId = examId;
}

public static long getSerialversionuid() {
return serialVersionUID;
}

/**
* 覆盖hashCode方法,必须要有
*/
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + (ip == null ? 0 : ip.hashCode());
result = PRIME * result + (examId == null ? 0 : examId.hashCode());
result = PRIME * result + (examPlaceId ==null ? 0 : examPlaceId.hashCode());
return result;
}

/**
* 覆盖equals方法,必须要有
*/
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
if(!(obj instanceof TestKey)) return false;
TestKey objKey = (TestKey)obj;
if(ip.equalsIgnoreCase(objKey.ip) &&
examId.equalsIgnoreCase(objKey.examId) &&
examPlaceId.equalsIgnoreCase(objKey.examPlaceId)) {
return true;
}
return false;
}
}


主类

package com.cmh.beans;

import javax.persistence.*;

/**
* Created by mianhai on 2017/2/15.
*/
@Entity
@Table(name="TE_IPMap")
@IdClass(TestKey.class)
public class ComponetIDKey {
// 主键,这里需要添加@Id标记
@Id
@Column(name="IP")
private String ip;

@Column(name="StudentNo")
private String studentNo;

// 主键,这里需要添加@Id标记
@Id
@Column(name="ExamPlaceId")
private String examPlaceId;

// 主键,这里需要添加@Id标记
@Id
@Column(name="ExamId", unique=true)
private String examId;

public String getIp() {
return ip;
}

public void setIp(String ip) {
this.ip = ip;
}

public String getStudentNo() {
return studentNo;
}

public void setStudentNo(String studentNo) {
this.studentNo = studentNo;
}

public String getExamPlaceId() {
return examPlaceId;
}

public void setExamPlaceId(String examPlaceId) {
this.examPlaceId = examPlaceId;
}

public String getExamId() {
return examId;
}

public void setExamId(String examId) {
this.examId = examId;
}
}


生成的sql如下:

create table te_ipmap (exam_id varchar(255) not null, exam_place_id varchar(255) not null, ip varchar(255) not null, student_no varchar(255), primary key (exam_id, exam_place_id, ip))


在主键类中,为了能使集合框架中的类(如HashMap)正常工作,必须同时覆盖equals和hashCode方法,而且不要由于写错参数类型,而重载了这个方法,却没有覆盖它们。

覆盖equals时总要覆盖hashCode,一个很常见的错误根源在没有覆盖hashCode方法。在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,这样的集合包括HashMap、HashSet和Hashtable。

——摘自《Effective Java》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hibernate