Hibernate复合主键

复合主键,由多个字段组成主键,例如,使用一个用户的firstname和lastname组成主键。

可以通过两种方式确定主键,一种是基于实体类的复合主键,另一种是通过定义主键类来实现。
不管通过哪种方式,复合主键都需要实现equals方法和hashcode方法,以作为不同数据之间是别的标志。

一.基于实体类属性的复合主键


主键由实体类中的属性组成。

1.映射文件TUser.hbm.xml

xml 代码
  1. <? xml version = "1.0" ?>   
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4. < hibernate-mapping>  
  5.      < class   name = "cn.blogjava.start.TUser"   table="t_user"   catalog = "sample" >   
  6.          < composite-id>  
  7.              < key-property   name ="lastname"  column = "lastname"   type ="string"   />  
  8.              < key-property name = "firstname"   column ="firstname"  type = "string"  />   
  9.          </ composite-id >   
  10.   
  11.          < property   name ="age"  type = "integer"  column ="age" />   
  12.      </ class>  
  13. </ hibernate-mapping>  

2.TUser.java

java 代码
  1. package cn.blogjava.start;   
  2.   
  3. import org.apache.commons.lang.builder.EqualsBuilder;   
  4. import org.apache.commons.lang.builder.HashCodeBuilder;   
  5.   
  6. /**  
  7.  * TUser generated by hbm2java 
  8.  */   
  9.   
  10. public class TUser implements java.io.Serializable {   
  11.   
  12.      // Fields      
  13.   
  14.      private Integer age;   
  15.   
  16.      private String firstname;   
  17.   
  18.      private String lastname;   
  19.   
  20.      public Integer getAge() {   
  21.          return age;   
  22.     }   
  23.   
  24.      public void setAge(Integer age) {   
  25.          this.age = age;   
  26.     }   
  27.   
  28.      public String getFirstname() {   
  29.          return firstname;   
  30.     }   
  31.   
  32.      public void setFirstname(String firstname) {   
  33.          this.firstname = firstname;   
  34.     }   
  35.   
  36.      public String getLastname() {   
  37.          return lastname;   
  38.     }   
  39.   
  40.      public void setLastname(String lastname) {   
  41.          this.lastname = lastname;   
  42.     }   
  43.        
  44.      public boolean equals(Object obj) {   
  45.          if(!(obj instanceof TUser)) {   
  46.              return false;   
  47.         }   
  48.            
  49.         TUser user = (TUser)obj;   
  50.          return new EqualsBuilder()          // EqualsBuilder 和HashCodeBuilder均为apache common lang包中的工具类  
  51.             .appendSuper( super.equals(obj))   
  52.             .append( this.lastname, user.lastname)   
  53.             .append( this.firstname, user.firstname)   
  54.             .isEquals();           
  55.     }   
  56.        
  57.      public int hasCode() {   
  58.          return new HashCodeBuilder(-528253723, - 475504089)   
  59.             .appendSuper( super.hashCode())   
  60.             .append( this.lastname).append(this.firstname)   
  61.             .toHashCode();   
  62.                
  63.     }   
  64.   
  65. }  

3.测试类HibernateTest.java

java 代码
  1. package cn.blogjava.start;   
  2.   
  3. import junit.framework.Assert;   
  4. import junit.framework.TestCase;   
  5.   
  6. import org.hibernate.HibernateException;   
  7. import org.hibernate.Session;   
  8. import org.hibernate.SessionFactory;   
  9. import org.hibernate.Transaction;   
  10. import org.hibernate.cfg.Configuration;   
  11.   
  12.   
  13. public class HibernateTest extends TestCase {   
  14.        
  15.     Session session =  null;   
  16.      /**  
  17.      * JUnit中的setUp方法在TestCase初始化的时候会自动调用 
  18.      * 一般用于初始化公用资源  
  19.      */  
  20.      protected void setUp() {   
  21.          try {   
  22.              /** 
  23.              * 可以采用hibernate.properties或者hibernate.cfg.xml 
  24.              * 配置文件的初始化代码 
  25.              *  
  26.              * 采用hibernate.properties 
  27.              * Configuration config = new Configuration(); 
  28.              * config.addClass(TUser.class); 
  29.              */  
  30.                
  31.              //采用hibernate.cfg.xml配置文件,与上面的方法对比,两个差异  
  32.              //1.Configuration的初始化方式  
  33.              //2.xml  
  34.             Configuration config =  new Configuration().configure();   
  35.             SessionFactory sessionFactory = config.buildSessionFactory();   
  36.             session = sessionFactory.openSession();   
  37.                
  38.         }  catch (HibernateException e) {   
  39.              // TODO: handle exception  
  40.             e.printStackTrace();   
  41.         }           
  42.     }   
  43.   
  44.      /**  
  45.      * JUnit中的tearDown方法在TestCase执行完毕的时候会自动调用 
  46.      * 一般用于释放资源  
  47.      */       
  48.      protected void tearDown() {   
  49.          try {   
  50.             session.close();           
  51.         }  catch (HibernateException e) {   
  52.              // TODO: handle exception  
  53.             e.printStackTrace();   
  54.         }           
  55.     }       
  56.        
  57.      /** 
  58.      * 对象持久化测试(Insert方法) 
  59.      */           
  60.      public void testInsert() {   
  61.         Transaction tran =  null;   
  62.          try {   
  63.             tran = session.beginTransaction();   
  64.             TUser user =  new TUser();   
  65.             user.setFirstname( "bai" );   
  66.             user.setLastname( "yunfeng");   
  67.             user.setAge( 26);   
  68.             session.save(user);   
  69.             session.flush();   
  70.             tran.commit();   
  71.         }  catch (HibernateException e) {   
  72.              // TODO: handle exception  
  73.             e.printStackTrace();   
  74.             Assert.fail(e.getMessage());   
  75.              if(tran != null) {   
  76.                  try {   
  77.                     tran.rollback();   
  78.                 }  catch (Exception e1) {   
  79.                      // TODO: handle exception  
  80.                     e1.printStackTrace();   
  81.                 }   
  82.             }   
  83.         }   
  84.     }   
  85.        
  86.      /**  
  87.      * 对象读取测试(Select方法) 
  88.      */                
  89.      public void testSelect(){   
  90.         TUser user =  new TUser();   
  91.         user.setFirstname( "bai");   
  92.         user.setLastname( "yunfeng");   
  93.            
  94.         user = (TUser)session.load(TUser. class , user);   
  95.         Assert.assertEquals(user.getAge().intValue(), 26);   
  96.     }   
  97. }   

二、基于主键类的复合主键:
方法:将主键字段从POJO类中提出了,生成一个主键类。
可以将1中的例子加以改造,将firstname和lastname字段单独提取到一个主键类中。

1.
配置文件TUser.hbm.xml
composite-id节点的name指定了实体类中的主键类的属性名.

xml 代码
  1. <? xml version = "1.0" ?>   
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  4. < hibernate-mapping package = "cn.blogjava.start" >   
  5.      < class   name = "TUser"   table ="t_user"  catalog = "sample" >   
  6.          < composite-id name = "userPK"   class = "TUserPK" >   
  7.              < key-property   name ="lastname"  column = "lastname"   type ="string"   />  
  8.              < key-property name = "firstname"   column ="firstname"  type = "string"  />   
  9.          </ composite-id >   
  10.   
  11.          < property   name ="age"  type = "integer"  column ="age" />   
  12.      </ class>  
  13. </ hibernate-mapping>  

2.POJO类

  1. package cn.blogjava.start;   
  2.   
  3. /** 
  4.  * TUser generated by hbm2java 
  5.  */  
  6.   
  7. public class TUser implements java.io.Serializable {   
  8.   
  9.      // Fields      
  10.   
  11.      private Integer age;   
  12.        
  13.      //配置文件composite-id的name属性  
  14.      private TUserPK userPK;   
  15.   
  16.   
  17.      public Integer getAge() {   
  18.          return age;   
  19.     }   
  20.   
  21.      public void setAge(Integer age) {   
  22.          this.age = age;   
  23.     }   
  24.   
  25.      public TUserPK getUserPK() {   
  26.          return userPK;   
  27.     }   
  28.   
  29.      public void setUserPK(TUserPK userPK) {   
  30.          this.userPK = userPK;   
  31.     }   
  32. }  

3.主键类TUserPK.java

java 代码
  1. package cn.blogjava.start;   
  2.   
  3. import java.io.Serializable;   
  4.   
  5. import org.apache.commons.lang.builder.EqualsBuilder;   
  6. import org.apache.commons.lang.builder.HashCodeBuilder;   
  7.   
  8. public class TUserPK implements Serializable {   
  9.   
  10.      private String firstname;   
  11.      private String lastname;   
  12.   
  13.      public String getFirstname() {   
  14.          return firstname;   
  15.     }   
  16.   
  17.      public void setFirstname(String firstname) {   
  18.          this.firstname = firstname;   
  19.     }   
  20.   
  21.      public String getLastname() {   
  22.          return lastname;   
  23.     }   
  24.   
  25.      public void setLastname(String lastname) {   
  26.          this.lastname = lastname;   
  27.     }   
  28.        
  29.      public boolean equals(Object obj) {   
  30.          if(!(obj instanceof TUserPK)) {   
  31.              return false;   
  32.         }   
  33.            
  34.         TUserPK userPK = (TUserPK)obj;   
  35.          return new EqualsBuilder()   
  36.             .appendSuper( super.equals(obj))   
  37.             .append( this.lastname, userPK.lastname)   
  38.             .append( this.firstname, userPK.firstname)   
  39.             .isEquals();           
  40.     }   
  41.        
  42.      public int hasCode() {   
  43.          return new HashCodeBuilder(-528253723, - 475504089)   
  44.             .appendSuper( super.hashCode())   
  45.             .append( this.lastname).append(this.firstname)   
  46.             .toHashCode();               
  47.     }   
  48. }   

4.测试代码HibernateTest.java

java 代码
  1. package cn.blogjava.start;   
  2.   
  3. import junit.framework.Assert;   
  4. import junit.framework.TestCase;   
  5.   
  6. import org.hibernate.HibernateException;   
  7. import org.hibernate.Session;   
  8. import org.hibernate.SessionFactory;   
  9. import org.hibernate.Transaction;   
  10. import org.hibernate.cfg.Configuration;   
  11.   
  12.   
  13. public class HibernateTest extends TestCase {   
  14.        
  15.     Session session =  null;   
  16.      /**  
  17.      * JUnit中的setUp方法在TestCase初始化的时候会自动调用 
  18.      * 一般用于初始化公用资源  
  19.      */  
  20.      protected void setUp() {   
  21.          try {   
  22.              /** 
  23.              * 可以采用hibernate.properties或者hibernate.cfg.xml 
  24.              * 配置文件的初始化代码 
  25.              *  
  26.              * 采用hibernate.properties 
  27.              * Configuration config = new Configuration(); 
  28.              * config.addClass(TUser.class); 
  29.              */  
  30.                
  31.              //采用hibernate.cfg.xml配置文件,与上面的方法对比,两个差异  
  32.              //1.Configuration的初始化方式  
  33.              //2.xml  
  34.             Configuration config =  new Configuration().configure();   
  35.             SessionFactory sessionFactory = config.buildSessionFactory();   
  36.             session = sessionFactory.openSession();   
  37.                
  38.         }  catch (HibernateException e) {   
  39.              // TODO: handle exception  
  40.             e.printStackTrace();   
  41.         }           
  42.     }   
  43.   
  44.      /**  
  45.      * JUnit中的tearDown方法在TestCase执行完毕的时候会自动调用 
  46.      * 一般用于释放资源  
  47.      */       
  48.      protected void tearDown() {   
  49.          try {   
  50.             session.close();           
  51.         }  catch (HibernateException e) {   
  52.              // TODO: handle exception  
  53.             e.printStackTrace();   
  54.         }           
  55.     }       
  56.        
  57.      /** 
  58.      * 对象持久化测试(Insert方法) 
  59.      */           
  60.      public void testInsert() {   
  61.         Transaction tran =  null;   
  62.          try {   
  63.             tran = session.beginTransaction();   
  64.             TUser user =  new TUser();   
  65.             TUserPK userPK =  new  TUserPK();   
  66.             userPK.setFirstname( "yu");   
  67.             userPK.setLastname( "yy" );   
  68.             user.setUserPK(userPK);   
  69.             user.setAge( 25);   
  70.             session.save(user);   
  71.             session.flush();   
  72.             tran.commit();   
  73.         }  catch (HibernateException e) {   
  74.              // TODO: handle exception  
  75.             e.printStackTrace();   
  76.             Assert.fail(e.getMessage());   
  77.              if(tran != null) {   
  78.                  try {   
  79.                     tran.rollback();   
  80.                 }  catch (Exception e1) {   
  81.                      // TODO: handle exception  
  82.                     e1.printStackTrace();   
  83.                 }   
  84.             }   
  85.         }   
  86.     }   
  87.        
  88.      /**  
  89.      * 对象读取测试(Select方法) 
  90.      */                
  91.      public void testSelect(){   
  92.         TUserPK userPK =  new TUserPK();   
  93.         userPK.setFirstname( "yu");   
  94.         userPK.setLastname( "yy");   
  95.            
  96.         TUser user = (TUser)session.load(TUser. class , userPK);   
  97.         Assert.assertEquals(user.getAge().intValue(), 25);   
  98.     }   
  99. }  

 

以上内容来自: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注解符号

     java 代码

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值