zoukankan      html  css  js  c++  java
  • Hibernate复合主键的注解

    [转自] http://blog.csdn.net/happylee6688/article/details/17636801



    最近做项目用到了Hibernate框架,采用了纯面向对象的思想,使用ORM映射实体。在开发中,实体中出现了复合主键,不再是单一的属性作主键,由于采用了注解的方式,就不再使用xml文件进行配置了,而是直接在实体中进行注释。


    Hibernate注解规范的文档中提供了三种方法

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

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

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

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


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

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

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

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


    主键类IPMapKey(为了方便演示,这里都采用了String类型)

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



    实体类IPMap(为了方便演示,这里都采用了String类型)
    @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;
    	}
    }


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

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

    ——摘自《Effective Java》

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

  • 相关阅读:
    笔记(用Python做些事情)--变量(数字、字符串)
    笔记(用Python做些事情)--变量(日期和时间)
    服务设计-ETL-核心框架
    zookeeper-服务-应用
    HBASE-表设计-优化
    HBASE-读取数据-优化
    HBASE-数据写入-优化
    Zookeeper-客户端-zkclient-curator
    KAFKA-使用问题
    HBASE-Spark操作hbase数据-思考
  • 原文地址:https://www.cnblogs.com/pekkle/p/6568694.html
Copyright © 2011-2022 走看看