Hibernate复合主键
2013-12-11 20:25
183 查看
复合主键,由多个字段组成主键,例如,使用一个用户的firstname和lastname组成主键。
可以通过两种方式确定主键,一种是基于实体类的复合主键,另一种是通过定义主键类来实现。
不管通过哪种方式,复合主键都需要实现equals方法和hashcode方法,以作为不同数据之间是别的标志。
一.基于实体类属性的复合主键
主键由实体类中的属性组成。
1.映射文件TUser.hbm.xml
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
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
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 代码
<? 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
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
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类
2. 主键类DoctorPK.java
在所有主键字段上加@Id注解符号
java 代码
3.测试代码
可以通过两种方式确定主键,一种是基于实体类的复合主键,另一种是通过定义主键类来实现。
不管通过哪种方式,复合主键都需要实现equals方法和hashcode方法,以作为不同数据之间是别的标志。
一.基于实体类属性的复合主键
主键由实体类中的属性组成。
1.映射文件TUser.hbm.xml
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
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
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 代码
<? 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
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
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注解符号
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); } }
相关文章推荐
- 两种方式配置Hibernate复合主键(修正)
- Hibernate的关联映射---6.1.9: 基于复合主键的关联关系
- Hibernate复合主键映射
- Hibernate 表映射 主键生成策略与复合主键
- Hibernate的复合主键映射
- SSH——Hibernate关联关系映射——复合主键
- Hibernate复合主键
- hibernate复合主键查询主键不能为空的解决方案
- Hibernate复合主键映射
- SSH:Hibernate框架(Hibernate复合主键映射)
- hibernate整合遗留数据库之处理主键(复合主键中的外键)
- Java程序员从笨鸟到菜鸟之(六十)细谈Hibernate(十一)hibernate复合主键映射
- Hibernate学习21 -- 关联映射11 -- 复合主键映射(composite-id)
- Hibernate中复合主键的用法
- Java的Hibernate框架中复合主键映射的创建和使用教程
- Hibernate 使用复合主键
- Hibernate的关联映射---6.1.10: 复合主键的成员属性为关联实体
- 步步为营Hibernate全攻略(四)剪不断理还乱之:复合主键 && 组合映射
- Hibernate征途(七)之复合主键映射和集合映射
- hibernate整合遗留数据库之处理主键(复合主键的外键)