網頁

2018/7/3

Hibernate JPA One To Many 複合鍵(Compound Key)設定

Hibernate JPA OneToMany複合鍵(Compound Key)設定如下。

本篇範例複合鍵是在子表(Many端)。

例如有三個資料表分別為DepartmentRegionEmployee關係如下。


                          +----------------+
                          |    Employee    |          +----------------+
+--------------+          +----------------+          |   Department   |
|    Region    |          |PK|EmployeeId   |*        1+----------------+
+--------------+1        *|FK|DepartmentId +----------+PK|DepartmentId |
|PK|RegionId   +----------+FK|RegionId     |          |  |             |
|  |           |          +----------------+          +--+-------------+
+--+-----------+


Employee的主鍵為複合主鍵,由本身的EmployeeId及外鍵RegionIdDepartmentId組成,則JPA的Entiy設定如下。

Employee.java

@Entity
@Table(name="Employee")
public class Employee {
    
    @EmbeddedId
    private EmployeePk employeePk;
    
    // getter and setter ommitted 
}

Employee因為是複合主鍵,所以要使用@EmbeddedId及一個@Embeddable類別EmployeePk來設定。

EmployeePk.java

@Embeddable
public class EmployeePk implements Serializable{
    
    @Column(name="EmployeeId")
    private int employeeId;
    
    @ManyToOne
    @JoinColumn(name="departmentId") // Department的@Id變數名稱
    private Department department;
    
    @ManyToOne
    @JoinColumn(name="regionId") // Region的@Id變數名稱
    private Region region;
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof EmployeePk)) return false;
        EmployeePk that = (EmployeePk) o;
        return (region.getRegionId() == that.region.getRegionId() &&
                department.getDepartmentId() == that.department.getDepartmentId() &&
                getEmployeeId() == that.getEmployeeId());
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(region.getRegionId(), department.getDepartmentId(), getEmployeeId());
    }

    // getter and setter ommitted
}

Department.java

@Entity
@Table(name="Department")
public class Department {
    
    @Id
    @Column(name="DepartmentId")
    private int departmentId;
    
    @OneToMany(mappedBy="employeePk.department") // Employee的@EmbeddedId變數名稱.@ManyToOne的變數名稱
    private List<Employee> employeeList;
    
}

注意@OneToManymappedBy屬性設定。而fetch維持預設的LAZY,不要設為EAGER,否則employeeList出現重複的資料

Region.java

@Entity
@Table(name="Region")
public class Region {
    
    @Id
    @Column(name="RegionId")
    private int regionId;
    
    @OneToMany(mappedBy="employeePk.region")
    private List<Employee> employeeList;
    
    // getter and setter ommitted 
}


下面是另一種設定方式,改用@MapId來指明EmployeePk中對應的屬性,效果相同

Employee.java

@Entity
@Table(name="Employee")
public class Employee {
    
    @EmbeddedId
    private EmployeePk employeePk;
 
    @MapsId("departmentId")
    @ManyToOne
    @JoinColumn(name="departmentId")
    private Department department;
    
    @MapsId("regionId")
    @ManyToOne
    @JoinColumn(name="regionId")
    private Region region;
    
    // getter and setter ommitted 
}

EmployeePk.java

@Embeddable
public class EmployeePk implements Serializable {
    
    @Column(name="EmployeeId")
    private int employeeId;
 
    public int departmentId;
    public int regionId;
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof EmployeePk)) return false;
        EmployeePk that = (EmployeePk) o;
        return (getRegionId() == that.getRegionId() &&
                getDepartmentId() == that.getDepartmentId() &&
                getEmployeeId() == that.getEmployeeId());
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(getRegionId(), getDepartmentId(), getEmployeeId());
    }
    // getter and setter ommitted 
}

DepartmentRegion設定同上。

然後@Embeddable類別要實作Serializable,否則會出現錯誤。


沒有留言:

張貼留言