hibernate复合主键

来源:互联网 发布:hidpi canvas.js下载 编辑:程序博客网 时间:2024/05/16 07:34
Hibernate的复合主键映射
原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和本声明。否则将追究法律责任。http://yangfei520.blog.51cto.com/1041581/310555
    1>.学过hibernate的都知道用<id>来配置主键生成策略,显然,它只能配置主键是单列的表,对于联合主键的情况<id>就无能为力了。今天翻到个复合主键映射的资料,觉得还是有一定价值的,就写了下来,以备后用。
    2>.hibernate处理复合主键映射是基于这样一种做法:把目标类中所有主键关联属性抽出来,单独写成一个类(我暂且叫它主键类),目标类就只需持有主键类对象,而不必再包含各个主键属性;在映射文件中使用<composite-id>标签来配置主键对象并指出关联属性,普通属性照常配置;hibernate只会创建一张表在,并且把主键设置为主键类各属性的联合主键,存储和加载数据时,会自然的把关联对象各属性跟表中的主键字段对应起来。在这个操作过程中,它要求主键类必须是序列化的,并且要覆盖equals方法,最好覆盖hashCode方法。(我试验过了,不覆盖equals和hashCode,结果没有出现任何问题,而且从输出的sql语句看,也没有影响数据库操作,不知道它是否还有更深的含义?还希望高手给指点下)
    3>.例子。一个规模较大公司的部门表(hibernate_dept_compositePK),由所在区域(area),部门名(name),本部门人数(empCount),组建时间(birthday)等字段组成,我们使用所在区域和部门名做联合主键:
 
1.目标类:Department.java
public class Department {
  /** 把主键关联属性抽象出来单独写成一个类 */
  //private String area;
  //private String name;
  /**把主键类对象作为成员变量*/
  private DepartmentPK departmentPK;
  private int empCount;
  private Date birthday;

//  public String getArea() {
//    return area;
//  }
//
//  public void setArea(String area) {
//    this.area = area;
//  }
//
//  public String getName() {
//    return name;
//  }
//
//  public void setName(String name) {
//    this.name = name;
//  }
    
  public int getEmpCount() {
    return empCount;
  }

  public void setEmpCount(int empCount) {
    this.empCount = empCount;
  }

  public Date getBirthday() {
    return birthday;
  }

  public void setBirthday(Date birthday) {
    this.birthday = birthday;
  }

  public DepartmentPK getDepartmentPK() {
    return departmentPK;
  }

  public void setDepartmentPK(DepartmentPK departmentPK) {
    this.departmentPK = departmentPK;
  }

}
2.主键类:DepartmentPK.java
public class DepartmentPKimplements Serializable {

  private staticfinal long serialVersionUID = -288002855915204255L;
  private String area;
  private String name;
  /**
    * 覆盖hashCode方法(根据area和name判断)
    */

  //@Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((area == null) ? 0 : area.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
  }
  /**
    * 覆盖equals(根据area和name判断)
    */

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    final DepartmentPK other = (DepartmentPK) obj;
    if (area == null) {
      if (other.area != null)
        return false;
    } else if (!area.equals(other.area))
      return false;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.equals(other.name))
      return false;
    return true;
  }

  public String getArea() {
    return area;
  }

  public void setArea(String area) {
    this.area = area;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}
3.映射文件Department.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC    
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="com.yangfei.hibernate.compositePk.entity.Department"table="hibernate_dept_compositePK">
    <!-- 联合主键 -->
    <!-- name指的是主键对象属性 -->
    <composite-idname="departmentPK">
      <!-- 这里是主键关联属性 -->
      <key-propertyname="area"/>
      <key-propertyname="name"/>
    </composite-id>
    <!-- 其它属性 -->
    <propertyname="empCount"length="4" />
    <propertyname="birthday"type="date"/>
  </class>
</hibernate-mapping>
4.hibernate配置文件hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
                    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                                    -->
<hibernate-configuration>
        <session-factory>
                <propertyname="dialect">org.hibernate.dialect.Oracle9Dialect</property>
                <propertyname="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:orcl10</property>
                <propertyname="connection.username">scott</property>
                <propertyname="connection.password">yf123</property>
                <propertyname="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
                <propertyname="hibernate.show_sql">true</property>
            
          <mappingresource="com/yangfei/hibernate/compositePk/entity/Department.hbm.xml"/>
        </session-factory>
</hibernate-configuration>
5.测试类:DepartmentTest.java
public class DepartmentTestextends TestCase {
  /**
    * 测试插入数据
    */

  public void save() {
    Session session = HibernateUtils.getSession();
    Transaction t = session.beginTransaction();
    try {
      Department dept = new Department();
      /** 生成主键对象 */
      DepartmentPK deptPK = new DepartmentPK();
      deptPK.setArea("北京");
      deptPK.setName("研发部");
      dept.setDepartmentPK(deptPK);

      dept.setEmpCount(100);
      dept.setBirthday(new Date());

      session.save(dept);
      t.commit();
    } catch (HibernateException e) {
      e.printStackTrace();
      t.rollback();
    } finally {
      HibernateUtils.closeSession(session);
    }
  }
  /**
    * 测试加载数据
    */

  public void load() {
    Session session = HibernateUtils.getSession();
    Transaction t = session.beginTransaction();
    try {
      /** 生成主键对象 */
      DepartmentPK deptPK = new DepartmentPK();
      deptPK.setArea("北京");
      deptPK.setName("研发部");

      Department dept=(Department)session.load(Department.class, deptPK);
      System.out.println(dept.getDepartmentPK().getArea()+","+dept.getDepartmentPK().getName()+","+dept.getEmpCount()+","+dept.getBirthday());
    } catch (HibernateException e) {
      e.printStackTrace();
      t.rollback();
    } finally {
      HibernateUtils.closeSession(session);
    }
  }
    
  /**
    * 测试修改数据
    */

  public void update() {
    Session session = HibernateUtils.getSession();
    Transaction t = session.beginTransaction();
    try {
      /** 生成主键对象 */
      DepartmentPK deptPK = new DepartmentPK();
      deptPK.setArea("北京");
      deptPK.setName("研发部");

      Department emp=(Department)session.load(Department.class, deptPK);
      System.out.println(emp.getDepartmentPK().getArea()+","+emp.getDepartmentPK().getName()+","+emp.getEmpCount()+","+emp.getBirthday());
      emp.setEmpCount(100);
      session.saveOrUpdate(emp);
        
      /** 生成主键对象 */
      DepartmentPK deptPK2 = new DepartmentPK();
      deptPK2.setArea("北京");
      deptPK2.setName("研发部");
      Department dept=(Department)session.load(Department.class, deptPK2);
      System.out.println(dept.getDepartmentPK().getArea()+","+dept.getDepartmentPK().getName()+","+dept.getEmpCount()+","+dept.getBirthday());
      t.commit();
    } catch (HibernateException e) {
      e.printStackTrace();
      t.rollback();
    } finally {
      HibernateUtils.closeSession(session);
    }
  }
    
  /**
    * 测试删除数据
    */

  public void delete() {
    Session session = HibernateUtils.getSession();
    Transaction t = session.beginTransaction();
    try {
      /** 生成主键对象 */
      DepartmentPK deptPK = new DepartmentPK();
      deptPK.setArea("北京");
      deptPK.setName("研发部");
        
      Department dept=(Department)session.load(Department.class, deptPK);
      session.delete(dept);
      t.commit();
    } catch (HibernateException e) {
      e.printStackTrace();
      t.rollback();
    } finally {
      HibernateUtils.closeSession(session);
    }
  }
}
 
4.一般来说,复合主键映射用起来是很复杂的,无论是开发时还是升级时。所以,人们往往宁愿选择增加个主键字段,也不尽量不采用它。
原创粉丝点击