1. 程式人生 > >Hibernate複合主鍵中其中有主鍵是引用外來鍵情況下的配置方法

Hibernate複合主鍵中其中有主鍵是引用外來鍵情況下的配置方法

這個有兩種配置方式。一種是對映一個也是複合主鍵一部分的外來鍵列,通過一般的<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版本中得以實現)。