hibernate 复合主键 注解

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

  1. 将类注解为@IdClass,并将该实体中所有主键属性注解为@Id。
    这里,我采用的是第三种方法——@IdClass,下面就是具体的代码,大家一块讨论一下。

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

    1. 主键类必须实现序列化接口(implements Serializable);
    2. 主键类必须有默认的public无参数的构造方法;
    3. 主键类必须覆盖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》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值