JPA:映射 ManyToMany 关系与附加 属性

JPA: Mapping ManyToMany relationship with additional property

我在 EmployeeSkillSet table 之间有多对多关系,每个关系都有额外的列 numberOfYears

employeeId  skillSetId  numberOfYears 
10          101         2

我是 JPA 的新手,无法定义具有关系的实体。我应该为 Employee_SkillSet table 定义一个新实体 class 吗?或者我可以在 EmployeeSkillSet class 中定义多对多关系吗?我在哪里指定 numberOfYears 列?

编辑:似乎重复,但我明确要求使用 @IdClass,其中一个实体是 @MappedSuperclass,因此必须同时定义 ID 实例和引用的实体对象。

由于元组 (Employee, SkillSet) 需要一个附加字段,因此您必须创建另一个实体。

@Entity
public class Employee implements Serializable {
    private @Id Long id;

    @OneToMany(mappedBy="employee")
    private List<EmployeeSkillSet> skillSets;
}

@Entity
public class SkillSet implements Serializable {
    private @Id Long id;
}

@Entity
public class EmployeeSkillSet implements Serializable {
    private @Id Long id;
    private @ManyToOne Employee employee;
    private @ManyToOne SkillSet skillSet;
    private @Basic int numberOfYears;
}

当然你可以选择使用 @IdClass 使 ("employee", "skillSet") 成为 EmployeeSkillSet 的主键,如下所示:

@Entity @IdClass(EmployeeSkillSet.Key.class)
public class EmployeeSkillSet implements Serializable {

    private @Id @ManyToOne Employee employee;
    private @Id @ManyToOne SkillSet skillSet;
    private @Basic int numberOfYears;

    public static class Key implements Serializable {
        private Long employee; // plus getter+setter
        private Long skillSet; // plus getter+setter
        // plus hashCode, equals
    }
}

尽管出于性能原因,您可以使用 @ManyToMany 批注更好,但定义两个多对一关系以便为多对多关系建模。

你需要4个神器,有

  • 员工实体
  • 技能组合实体
  • EmployeeSkillSet Relation实体(这里可以指定numberOfYears列)
  • EmployeeSkillSetPK(EmployeeSkillSet 关系实体的主键)

代码应该是这样的

员工

package <your_package>;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 *
 */
@Entity
@Table(name="EMPLOYEE")
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="EMPLOYEEID")
    private int id;

    // Rest of columns and getter and setters for all
}

技能组合

package <your_package>;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 *
 */
@Entity
@Table(name="SKILLSET")
public class SkillSet implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="SKILLSETID")
    private int id;

    // Rest of columns and getter and setters for all
}

EmployeeSkillSetPK

/**
 * 
 */
package <your_package>;

import java.io.Serializable;

import javax.persistence.Embeddable;

/**
 *
 */
@Embeddable
public class EmployeeSkillSetPK implements Serializable {

    @ManyToOne
    private Employee emp;

    @ManyToOne
    private SkillSet sk;
    /**
     * @return the employee
     */
    public Employee getEmployee() {
        return emp;
    }
    /**
     * @param employee the employee to set
     */
    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
    /**
     * @return the sk
     */
    public SkillSet getSkillSet() {
        return sk;
    }
    /**
     * @param sk the sk to set
     */
    public void setSkillSet(SkillSet sk) {
        this.sk = sk;
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        EmployeeSkillSetPK that = (EmployeeSkillSetPK) o;

        if (employee != null ? !employee.equals(that.employee) : that.employee != null) {
            return false;
        }
        if (sk != null ? !sk.equals(that.sk) : that.sk != null) {
            return false;
        }

        return true;
    }

    public int hashCode() {
        int result;
        result = (employee != null ? employee.hashCode() : 0);
        result = 31 * result + (sk != null ? sk.hashCode() : 0);
        return result;
    }
}

EmployeeSkillSet

/**
 * 
 */
package <your_package>;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 *
 */
@Entity
@Table(name="EMPLOYEESKILLSET")
    @AssociationOverrides({ @AssociationOverride(name = "pk.employee", joinColumns = @JoinColumn(name = "EMPLOYEEID")),
    @AssociationOverride(name = "pk.sk", joinColumns = @JoinColumn(name = "SKILLSETID")) })
public class EmployeeSkillSet implements Serializable {

    @EmbeddedId
    private EmployeeSkillSetPK pk = new EmployeeSkillSetPK();

    @Column 
    private Integer numberOfYears;

    @Transient
    public Employee getEmployee() {
        return pk.getEmployee();
    }

    public void setEmployee(Employee employee) {
        pk.setEmployee(employee);
    }

    @Transient
    public SkillSet getSkillSet() {
        return pk.getSkillSet();
    }

    public void setSkillSet(SkillSet sk) {
        pk.setSkillSet(sk);
    }

    public Integer getNumbersOfYears() {
        return numberOfYears;
    }

    public void setNumbersOfYears(Integer numberOfYears) {
        this.numberOfYears = numberOfYears;
    } 
}

这是针对 JPA 1.0 的,我现在无法测试代码,但它应该可以工作。

请注意,table 和列名是我自己写的。随意改编。