这个有两种配置方式。一种是映射一个也是复合主键一部分的外键列,通过一般的<many-to-one>元素,并用insert="false" update="false"禁用该列的任何Hibernate插入或者更新。另一种方式是<key-many-to-one>。下面分别说明两种方式的配置方法。
1、many-to-one方式
假设有两个表USER和DEPARTMENT表。两个表的结构创建SQL语句如下:
create table DEPARTMENT (
DEPARTMENT_ID varchar(255) not null,
DEPARTMENT_NAME varchar(255),
DEPARTMENT_ADDRESS varchar(255),
primary key (DEPARTMENT_ID)
);
create table USER (
USERNAME varchar(255) not null,
DEPARTMENT_ID varchar(255) not null,
FIRSTNAME varchar(255),
LASTNAME varchar(255),
primary key (USERNAME, DEPARTMENT_ID)
);
alter table USER
add constraint FK27E3CBF9776336
foreign key (DEPARTMENT_ID)
references DEPARTMENT;
可以看到USER表的主键是由(USERNAME, DEPARTMENT_ID)联合主键构成的。其中列DEPARTMENT_ID是引用表DEPARTMENT中DEPARTMENT_ID列的外键。
根据表结构生成的Java类如下:
首先需要构建一个联合主键类UserId.java
package hello;
import java.io.Serializable;
/**
* Created by orz on 16-2-28.
*/
public class UserId implements Serializable {
private String username;
private String departmentId;
public UserId() {
}
public UserId(String username, String departmentId) {
this.username = username;
this.departmentId = departmentId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getDepartmentId() {
return departmentId;
}
public void setDepartmentId(String departmentId) {
this.departmentId = departmentId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserId userId = (UserId) o;
if (username != null ? !username.equals(userId.username) : userId.username != null) return false;
return departmentId != null ? departmentId.equals(userId.departmentId) : userId.departmentId == null;
}
@Override
public int hashCode() {
int result = username != null ? username.hashCode() : 0;
result = 31 * result + (departmentId != null ? departmentId.hashCode() : 0);
return result;
}
}
User.java 如下:
package hello;
/**
* Created by orz on 16-2-28.
*/
public class User {
private UserId userId;
private String firstName;
private String lastName;
private Department department;
public UserId getUserId() {
return userId;
}
public void setUserId(UserId userId) {
this.userId = userId;
}
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 Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
}
Department.java 如下:
package hello;
/**
* Created by orz on 16-2-28.
*/
public class Department {
private String departmentId;
private String departmentName;
private String address;
public String getDepartmentId() {
return departmentId;
}
public void setDepartmentId(String departmentId) {
this.departmentId = departmentId;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
创建的配置文件如下:
Department.hbm.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hello.Department" table="DEPARTMENT">
<id name="departmentId" column="DEPARTMENT_ID">
<generator class="assigned" />
</id>
<property name="departmentName" column = "DEPARTMENT_NAME" />
<property name="address" column = "DEPARTMENT_ADDRESS" />
</class>
</hibernate-mapping>
User.hbm.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hello.User" table="USER">
<composite-id name="userId" class="hello.UserId">
<key-property name="username" column="USERNAME" />
<key-property name="departmentId" column="DEPARTMENT_ID" />
</composite-id>
<property name="firstName" column = "FIRSTNAME" />
<property name="lastName" column = "LASTNAME" />
<many-to-one name="department" class="hello.Department" column="DEPARTMENT_ID" insert="false" update="false" />
</class>
</hibernate-mapping>
测试类如下:
package hello;
import org.hibernate.Session;
import org.hibernate.Transaction;
import persistence.HibernateUtil;
import java.util.Iterator;
import java.util.List;
/**
* Created by orz on 16-2-21.
*/
public class HelloWorld {
public static void main(String[] args) {
Session departmentSession = HibernateUtil.getSessionFactory().openSession();
Transaction departmentTa = departmentSession.beginTransaction();
Department department = new Department();
department.setDepartmentId("1");
department.setDepartmentName("university");
department.setAddress("xi'an");
departmentSession.save(department);
departmentTa.commit();
departmentSession.close();
Session userSession1 = HibernateUtil.getSessionFactory().openSession();
Transaction userTa1 = userSession1.beginTransaction();
UserId userId = new UserId("zxwei",department.getDepartmentId());
User user = new User();
user.setUserId(userId);
user.setFirstName("zx");
user.setLastName("wei");
user.setDepartment(department);
userSession1.saveOrUpdate(user);
userTa1.commit();
userSession1.close();
Session userSession2 = HibernateUtil.getSessionFactory().openSession();
Transaction userTa2 = userSession2.beginTransaction();
List users = userSession2.createQuery("from User u").list();
System.out.println(users.size() + " user(s) found");
for (Iterator iter = users.iterator(); iter.hasNext();) {
User iuser = (User) iter.next();
System.out.println("User: " + iuser.getUserId().getUsername() + ", "
+ iuser.getUserId().getDepartmentId() + ", " + iuser.getFirstName() + ", " + iuser.getLastName()
+", department: " + iuser.getDepartment().getDepartmentName() + ", " + iuser.getDepartment().getAddress());
}
userTa2.commit();
userSession2.close();
//Shutting down the application
HibernateUtil.shutdown();
}
}
经测试成功运行。其中的HibernateUtil类可以参考我的另一篇博客:“ Hibernate one-to-one 复合主键相同的mapping文件配置方法 ”。
2、key-many-to-one方式
大致的配置如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hello.User" table="USER">
<composite-id name="userId" class="hello.UserId">
<key-property name="username" column="USERNAME" />
<key-many-to-one name="department" class="hello.Department" column="DEPARTMENT_ID" />
</composite-id>
<property name="firstName" column = "FIRSTNAME" />
<property name="lastName" column = "LASTNAME" />
</class>
</hibernate-mapping>
这个我没有经过测试。不建议使用这种方式。因为在复合标识类中有关联通常并不方便,因此除非特殊情况下,否则不推荐这种方法。<key-many-to-one>构造在查询方面也有限制:你无法限制一个跨<key-many-to-one>联接的HQL或者Criteria的查询结果(虽然这些特性可能将在以后的HIbernate版本中得以实现)。