Hibernate通过注解实现复合主键

Hibernate注解规范的文档中提供了三种方法:
1. 将组件类注解为@Embeddable,并将组件的属性注解为@Id;
2. 将组件的属性注解为@Embeddable;
3. 将类注解为@IdClass,并将该实体中所有主键属性注解为@Id。
这里,我采用的是第三种方法——@IdClass,下面就是具体的代码,大家一块讨论一下。

   首先,需要说明的是,采用@IdClass方式,需要根据所有的主键属性,建立一个主键类,该主键类包含所有的主键,而且,作为主键类,需要满足以下要求:
1. 主键类必须实现序列化接口(implements Serializable);
2. 主键类必须有默认的public无参数的构造方法;
3. 主键类必须覆盖equals和hashCode方法。

主键类IPMapKey(为了方便演示,这里都采用了String类型)
[java] view plaincopy在CODE上查看代码片派生到我的代码片
public class IPMapKey implements Serializable {

   /** 
     * @Fields serialVersionUID :3176972128965536016L 
     */  
    private static final long serialVersionUID = 3176972128965536016L;  

    // 主键属性  
    private String ip;  

    // 主键属性  
    private String examPlaceId;  

    // 主键属性  
    private String examId;  

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

    }  

    /** 
     * 重写了一个带参数的构造方法 
     * @param ip 
     * @param examPlaceId 
     * @param examId 
     */  
    public IPMapKey(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 PaperKey)) return false;  
        IPMapKey objKey = (IPMapKey)obj;  
        if(ip.equalsIgnoreCase(objKey.ip) &&  
                examId.equalsIgnoreCase(objKey.examId) &&   
                examPlaceId.equalsIgnoreCase(objKey.examPlaceId)) {  
            return true;  
        }  
        return false;  
    }  
}</span>  

实体类IPMap(为了方便演示,这里都采用了String类型)

[java] view plaincopy在CODE上查看代码片派生到我的代码片
<span style="font-family:Microsoft YaHei;font-size:14px;">@Entity  
@Table(name="TE_IPMap")  
@IdClass(IPMapKey.class)  
public class IPMap {  

    // 主键,这里需要添加@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;  

    @Column(name="AddUser")  
    private String addUser;  

    @Column(name="TimeStamp")  
    private String timeStamp;  

    @Column(name="Remark")  
    private String remark;  

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

    public String getAddUser() {  
        return addUser;  
    }  

    public void setAddUser(String addUser) {  
        this.addUser = addUser;  
    }  

    public String getTimeStamp() {  
        return timeStamp;  
    }  

    public void setTimeStamp(String timeStamp) {  
        this.timeStamp = timeStamp;  
    }  

    public String getRemark() {  
        return remark;  
    }  

    public void setRemark(String remark) {  
        this.remark = remark;  
    }  
}</span>  
   在主键类中,为了能使集合框架中的类(如HashMap)正常工作,必须同时覆盖equals和hashCode方法,而且不要由于写错参数类型,而重载了这个方法,却没有覆盖它们。
   覆盖equals时总要覆盖hashCode,一个很常见的错误根源在没有覆盖hashCode方法。在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常工作,这样的集合包括HashMap、HashSet和Hashtable。

——摘自《Effective Java》
equals方法用于判断传入的对象是否相同,EntityManager通过find方法来查找Entity时,是根据equals方法的返回值来判断的。hashCode方法返回当前对象的哈希码,生成的hashCode相同的概率越小越好。

李祥

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值