复合主键,由多个字段组成主键,例如,使用一个用户的firstname和lastname组成主键。
可以通过两种方式确定主键,一种是基于实体类的复合主键,另一种是通过定义主键类来实现。
不管通过哪种方式,复合主键都需要实现equals方法和hashcode方法,以作为不同数据之间是别的标志。
一.基于实体类属性的复合主键
主键由实体类中的属性组成。
1.映射文件TUser.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 = "cn.blogjava.start.TUser" table="t_user" catalog = "sample" >
- < composite-id>
- < key-property name ="lastname" column = "lastname" type ="string" />
- < key-property name = "firstname" column ="firstname" type = "string" />
- </ composite-id >
- < property name ="age" type = "integer" column ="age" />
- </ class>
- </ hibernate-mapping>
2.TUser.java
- package cn.blogjava.start;
- import org.apache.commons.lang.builder.EqualsBuilder;
- import org.apache.commons.lang.builder.HashCodeBuilder;
- /**
- * TUser generated by hbm2java
- */
- public class TUser implements java.io.Serializable {
- // Fields
- private Integer age;
- private String firstname;
- private String lastname;
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- 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;
- }
- public boolean equals(Object obj) {
- if(!(obj instanceof TUser)) {
- return false;
- }
- TUser user = (TUser)obj;
- return new EqualsBuilder() // EqualsBuilder 和HashCodeBuilder均为apache common lang包中的工具类
- .appendSuper( super.equals(obj))
- .append( this.lastname, user.lastname)
- .append( this.firstname, user.firstname)
- .isEquals();
- }
- public int hasCode() {
- return new HashCodeBuilder(-528253723, - 475504089)
- .appendSuper( super.hashCode())
- .append( this.lastname).append(this.firstname)
- .toHashCode();
- }
- }
3.测试类HibernateTest.java
- package cn.blogjava.start;
- import junit.framework.Assert;
- import junit.framework.TestCase;
- import org.hibernate.HibernateException;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- public class HibernateTest extends TestCase {
- Session session = null;
- /**
- * JUnit中的setUp方法在TestCase初始化的时候会自动调用
- * 一般用于初始化公用资源
- */
- protected void setUp() {
- try {
- /**
- * 可以采用hibernate.properties或者hibernate.cfg.xml
- * 配置文件的初始化代码
- *
- * 采用hibernate.properties
- * Configuration config = new Configuration();
- * config.addClass(TUser.class);
- */
- //采用hibernate.cfg.xml配置文件,与上面的方法对比,两个差异
- //1.Configuration的初始化方式
- //2.xml
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- session = sessionFactory.openSession();
- } catch (HibernateException e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- /**
- * JUnit中的tearDown方法在TestCase执行完毕的时候会自动调用
- * 一般用于释放资源
- */
- protected void tearDown() {
- try {
- session.close();
- } catch (HibernateException e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- /**
- * 对象持久化测试(Insert方法)
- */
- public void testInsert() {
- Transaction tran = null;
- try {
- tran = session.beginTransaction();
- TUser user = new TUser();
- user.setFirstname( "bai" );
- user.setLastname( "yunfeng");
- user.setAge( 26);
- session.save(user);
- session.flush();
- tran.commit();
- } catch (HibernateException e) {
- // TODO: handle exception
- e.printStackTrace();
- Assert.fail(e.getMessage());
- if(tran != null) {
- try {
- tran.rollback();
- } catch (Exception e1) {
- // TODO: handle exception
- e1.printStackTrace();
- }
- }
- }
- }
- /**
- * 对象读取测试(Select方法)
- */
- public void testSelect(){
- TUser user = new TUser();
- user.setFirstname( "bai");
- user.setLastname( "yunfeng");
- user = (TUser)session.load(TUser. class , user);
- Assert.assertEquals(user.getAge().intValue(), 26);
- }
- }
二、基于主键类的复合主键:
方法:将主键字段从POJO类中提出了,生成一个主键类。
可以将1中的例子加以改造,将firstname和lastname字段单独提取到一个主键类中。
1.
配置文件TUser.hbm.xml
composite-id节点的name指定了实体类中的主键类的属性名.
- <? 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 package = "cn.blogjava.start" >
- < class name = "TUser" table ="t_user" catalog = "sample" >
- < composite-id name = "userPK" class = "TUserPK" >
- < key-property name ="lastname" column = "lastname" type ="string" />
- < key-property name = "firstname" column ="firstname" type = "string" />
- </ composite-id >
- < property name ="age" type = "integer" column ="age" />
- </ class>
- </ hibernate-mapping>
2.POJO类
- package cn.blogjava.start;
- /**
- * TUser generated by hbm2java
- */
- public class TUser implements java.io.Serializable {
- // Fields
- private Integer age;
- //配置文件composite-id的name属性
- private TUserPK userPK;
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- public TUserPK getUserPK() {
- return userPK;
- }
- public void setUserPK(TUserPK userPK) {
- this.userPK = userPK;
- }
- }
3.主键类TUserPK.java
- package cn.blogjava.start;
- import java.io.Serializable;
- import org.apache.commons.lang.builder.EqualsBuilder;
- import org.apache.commons.lang.builder.HashCodeBuilder;
- public class TUserPK implements Serializable {
- private String firstname;
- private String lastname;
- 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;
- }
- public boolean equals(Object obj) {
- if(!(obj instanceof TUserPK)) {
- return false;
- }
- TUserPK userPK = (TUserPK)obj;
- return new EqualsBuilder()
- .appendSuper( super.equals(obj))
- .append( this.lastname, userPK.lastname)
- .append( this.firstname, userPK.firstname)
- .isEquals();
- }
- public int hasCode() {
- return new HashCodeBuilder(-528253723, - 475504089)
- .appendSuper( super.hashCode())
- .append( this.lastname).append(this.firstname)
- .toHashCode();
- }
- }
4.测试代码HibernateTest.java
- package cn.blogjava.start;
- import junit.framework.Assert;
- import junit.framework.TestCase;
- import org.hibernate.HibernateException;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import org.hibernate.cfg.Configuration;
- public class HibernateTest extends TestCase {
- Session session = null;
- /**
- * JUnit中的setUp方法在TestCase初始化的时候会自动调用
- * 一般用于初始化公用资源
- */
- protected void setUp() {
- try {
- /**
- * 可以采用hibernate.properties或者hibernate.cfg.xml
- * 配置文件的初始化代码
- *
- * 采用hibernate.properties
- * Configuration config = new Configuration();
- * config.addClass(TUser.class);
- */
- //采用hibernate.cfg.xml配置文件,与上面的方法对比,两个差异
- //1.Configuration的初始化方式
- //2.xml
- Configuration config = new Configuration().configure();
- SessionFactory sessionFactory = config.buildSessionFactory();
- session = sessionFactory.openSession();
- } catch (HibernateException e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- /**
- * JUnit中的tearDown方法在TestCase执行完毕的时候会自动调用
- * 一般用于释放资源
- */
- protected void tearDown() {
- try {
- session.close();
- } catch (HibernateException e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- /**
- * 对象持久化测试(Insert方法)
- */
- public void testInsert() {
- Transaction tran = null;
- try {
- tran = session.beginTransaction();
- TUser user = new TUser();
- TUserPK userPK = new TUserPK();
- userPK.setFirstname( "yu");
- userPK.setLastname( "yy" );
- user.setUserPK(userPK);
- user.setAge( 25);
- session.save(user);
- session.flush();
- tran.commit();
- } catch (HibernateException e) {
- // TODO: handle exception
- e.printStackTrace();
- Assert.fail(e.getMessage());
- if(tran != null) {
- try {
- tran.rollback();
- } catch (Exception e1) {
- // TODO: handle exception
- e1.printStackTrace();
- }
- }
- }
- }
- /**
- * 对象读取测试(Select方法)
- */
- public void testSelect(){
- TUserPK userPK = new TUserPK();
- userPK.setFirstname( "yu");
- userPK.setLastname( "yy");
- TUser user = (TUser)session.load(TUser. class , userPK);
- Assert.assertEquals(user.getAge().intValue(), 25);
- }
- }
以上内容来自:http://www.blogjava.net/zoninge/archive/2009/01/05/249928.html
三 复合主键注解方式
联合主键用Hibernate注解映射方式主要有三种:
第一、将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并重写equals和hascode,再将该类注解为@Embeddable,最后在主类中(该类不包含联合
主键类中的字段)保存该联合主键类的一个引用,并生成set和get方法,并将该引用注解为@Id
第二、将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并重写equals和hascode,最后在主类中(该类不包含联合主键类中的字段)保存该联合主
键类的一个引用,并生成set和get方法,并将该引用注解为@EmbeddedId
第三、将联合主键的字段单独放在一个类中,该类需要实现java.io.Serializable接口并要重写equals和hashcode.最后在主类中(该类包含联合主键类中的字段)将联合主键字
段都注解为@Id,并在该类上方将上这样的注解:@IdClass(联合主键类.class)
下面以第三种方式举例:
1.POJO类
package com.red.bean;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.IdClass;
import javax.persistence.Table;
@Entity
@IdClass(DoctorPK.class)
@Table(name="t_doctor")
public class Doctor implements Serializable
{
private static final long serialVersionUID = 1L;
private DoctorPK doctorpk = null;
private String sex = "";
public DoctorPK getDoctorpk() {
return doctorpk;
}
public void setDoctorpk(DoctorPK doctorpk) {
this.doctorpk = doctorpk;
}
public String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
}
2. 主键类DoctorPK.java
在所有主键字段上加@Id注解符号
package com.red.bean;
import java.io.Serializable;
import javax.persistence.Id;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class DoctorPK implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
private String firstName = "";
@Id
private String lastName = "";
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;
}
public int hasCode()
{
return new HashCodeBuilder(- 528253723, - 475504089 )
.appendSuper( super.hashCode())
.append( this.lastName).append( this.firstName)
.toHashCode();
}
public boolean equals(Object obj)
{
if(!(obj instanceof DoctorPK))
{
return false;
}
DoctorPK userPK = (DoctorPK)obj;
return new EqualsBuilder()
.appendSuper( super.equals(obj))
.append( this.lastName, userPK.lastName)
.append( this.firstName, userPK.firstName)
.isEquals();
}
}
3.测试代码
package com.red.test;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import com.red.bean.Doctor;
import com.red.bean.DoctorPK;
import junit.framework.Assert;
import junit.framework.TestCase;
public class TestDoactorCase extends TestCase {
private Session session = null;
private SessionFactory sf = null;
protected void setUp()
{
try
{
AnnotationConfiguration cfg = new AnnotationConfiguration();
sf = cfg.configure().buildSessionFactory();
session = sf.openSession();
}
catch( HibernateException e)
{
e.printStackTrace();
}
}
protected void tearDown()
{
try
{
session.close();
sf.close();
}
catch(HibernateException e)
{
e.printStackTrace();
}
}
public void testInsert()
{
try
{
DoctorPK docpk = new DoctorPK();
docpk.setFirstName("li");
docpk.setLastName("guoliang");
Doctor dc = new Doctor();
dc.setSex("0");
dc.setDoctorpk(docpk);
session.beginTransaction();
session.save(dc);
session.getTransaction().commit();
}
catch (HibernateException e)
{
e.printStackTrace();
}
}
public void testSelect()
{
DoctorPK docpk = new DoctorPK();
docpk.setFirstName("li");
docpk.setLastName("guoliang");
Doctor dr = (Doctor) session.load(Doctor.class, docpk);
Assert.assertEquals("0".equals(dr.getSex()) , true);
}
}