【Hibernate集锦】---复合主键映射


   我们都熟知,当合同到期后需要同公司进行合同续签,如果合同信息有变化或者内容有误等都需要进行合同变

更。为了保留历史数据,公司的做法一般都是封版现有生效的合同然后插入新的合同信息,这样每个员工都有一条或

者多条合同信息。在这种应用场景下一个主键id已经不能满足需求了,这时候我们可以考虑给它提供另外一个标识信

息来过滤当前有效信息,这样由多个字段组合成的主键即复合主键。这里假设以员工id和合同起始日期为主键来进行

讲解。


   复合主键映射,通常需要将主键相关字段放到一个单独的类中进行维护。对于复合主键类需要满足两个要求:

     * 1.实现序列化接口
     * 2.覆盖equals和hashcode方法

    equals方法用于判断传入的对象是否相同,EntityManager通过find方法来查找Entity时,是根据equals方法的

返回值来判断的。而为了保证该类可以结合所有基于散列的集合一起正常工作,同时需要覆盖hashcode方法。


下面结合源码解析一步步进行讲解。复合主键类:

import java.io.Serializable;
import java.util.Date;

/**
 * 员工合同复合主键类
 * 1.实现序列化接口
 * 2.覆盖equals和hashcode方法
 * @author WYQ
 *
 */
public class ContractPK implements Serializable {

	//员工code
	private String employeeCode;
	
	//合同开始日期
	private Date startDate;

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((employeeCode == null) ? 0 : employeeCode.hashCode());
		result = prime * result
				+ ((startDate == null) ? 0 : startDate.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ContractPK other = (ContractPK) obj;
		if (employeeCode == null) {
			if (other.employeeCode != null)
				return false;
		} else if (!employeeCode.equals(other.employeeCode))
			return false;
		if (startDate == null) {
			if (other.startDate != null)
				return false;
		} else if (!startDate.equals(other.startDate))
			return false;
		return true;
	}

	//getter{...}  setter{...}
	
	
}


员工合同类,需要将上面定义的复合主键类注入到该主体类中:

import java.util.Date;

/**
 * 员工合同类
 * @author WYQ
 *
 */
public class EmployeeContract {
	
	//注入复合主键
	private ContractPK contractPK;
	
	//合同类型,1.首签 2.续签 3.变更
	private int contractType;
	
	//合同详情
	private String content;
	
	//合同截止日期
	private Date endDate;

	
	//getter{...}  setter{...}
	

}
</span></span>

 

   将实体类的映射信息添加到EmployeeContract.hbm.xml配置文件中。需要注意的是,这里主键标识不再是id,id

是用来标识单一主键的标签,而composite-id是用来标识复合主键的标签,将复合主键中字段都添加到配置文件中。

<?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.bjpowernode.hibernate.EmployeeContract" table="t_employeeContract">
		<composite-id name="contractPK">
			<key-property name="employeeCode"/>
			<key-property name="startDate"/>
		</composite-id>

		<property name="contractType" type="int"/>
		<property name="content" type="string"/>
		<property name="endDate" type="date"/>
	</class>
</hibernate-mapping>


接下来就是将映射文件添加到hibernate配置文件中,连接数据库了。

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory>
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/employeeContract</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">123456</property>
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="hibernate.show_sql">true</property>
		
		<mapping resource="com/bjpowernode/hibernate/EmployeeContract.hbm.xml"/>
	</session-factory>
</hibernate-configuration>


执行mysql命令创建数据库,数据库名称即hibernate配置文件中配置的employeeContract。


创建好数据库,接下来就是创建表了。执行hibernate导出数据库脚本工具类:

import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

/**
 * hibernate导出数据库工具类
 * @author Administrator
 *
 */
public class ExportDB {

	public static void main(String[] args) {
		
		//默认读取hibernate.cfg.xml文件
		Configuration cfg = new Configuration().configure();
		
		SchemaExport export = new SchemaExport(cfg);
		export.create(true, true);
	}
}


在控制台中我们可以看到hibernate自动生成的创建表的语句,其中复合主键均满足非空条件。


最后创建一个单元测试类来测试一下我们的复合主键应用。

import java.text.SimpleDateFormat;
import java.util.Date;

import junit.framework.TestCase;

import org.hibernate.Session;

public class CompositePKMappingTest extends TestCase {

	/**
	 * 添加一条合同信息
	 */
	public void testSave1() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			//实例化合同对象
			EmployeeContract empContract=new EmployeeContract();
			
			//初始化复合主键
			ContractPK contractPK =new ContractPK();
			contractPK.setEmployeeCode("0001");
			contractPK.setStartDate(new Date());
			//将主键添加到合同对象
			empContract.setContractPK(contractPK);
			
			//初始化普通属性
			empContract.setContent("员工test自愿与复合主键测试公司签订劳动合同,即日起生效!");
			empContract.setContractType(1);
			empContract.setEndDate(new Date());
			session.save(empContract);
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}


运行该测试方法,hibernate自动生成的sql语句如下:

<span style="font-family:KaiTi_GB2312;font-size:18px;">Hibernate: insert into t_employeeContract (contractType, content, endDate, employeeCode, startDate) values (?, ?, ?, ?, ?)</span>


   复合主键最明显的优点就是比较直观,在查询的时候写sql语句会轻松些,在不需要有很多关联的表可以使用。

但是复合主键的应用也会带来很多负面影响,例如:

   *1.增加了表之间的耦合性

   *2.存在严重的数据冗余

   *3.对用户更新数据的限制大大提高

      * ...

   总之,对于复合键来说,其缺点大于优点,故此,数据库设计规范中都建议避免使用复合键!




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值