JPA,关系初学者多对多,有一定的复杂性

JPA,RELATIONSHIP BEGINEER MANY TO MANY with some complexity

我的领域模型中有 4 个实体,它们是教授大学部门和角色。 用例是

  1. 教授只能为一对多的一所大学工作 关系(学院 -> 教授)
  2. 教授将在大学级别担任许多角色(管理员、食品检查员??)
  3. 教授可以为多个部门工作(多对多)
  4. 在每个系教授可能扮演不同的角色

    class Professor {
        @ManyToOne
        private College workingWithCollege;
        @JoinTable(name = "professor_college_role",
                   joinColumns = @JoinColumn(name = "professor_id"),
                   inverseJoinColumns = @JoinColumn(name = "role_id"))
        @OneToMany
        private Collection<Role> roles;
     }
    
    class College {
    
    }
    
    
    class Department {
    
    }
    
    class DepartMentRole {
        @ManyToOne
        private Department department;
        @ManyToOne
        private Role role;
        //TODO: Dont know how exactly to solve this
    }
    
    class ProfessorDepartmentRole {
         @OneToOne
         private Professor professor;
         @OneToMany
         private Collection DepartmentRole;
    }
    

我们真的需要部门角色吗?如何将教授与部门联系起来以及该部门的角色

我会将 ProfessorDepartmentRole class 转换为多对多(如 KLibby 所建议)。因此,为了回答您的问题,我们确实保留了 DepartmentRole class。此外,您还可以从 Professor class 中删除集合角色,因为您可以通过 2 个连接表派生角色。

实现所涉及的实体及其映射之间的关系的方法有很多种。

您定义实体:CollegeProfessorDepartmentRole

现在的问题是如何定义 Professor 在特定 Role 中为 Department 工作之间的关系。一种方法是将这种关系表示为另一个实体——我们称之为 ProfessorDepartment

ProfessorDepartment 实体之间的多对多关系仍然可以使用 ProfessorDepartment 作为 "relationship state"/ "association class" 在 2 个实体之间,如 ff 中所示。映射:

  • ProfessorProfessorDepartment的关系是一对多
  • ProfessorDepartmentProfessor 的关系是多对一(双向)
  • DepartmentProfessorDepartment的关系是一对多
  • ProfessorDepartmentDepartment 的关系是多对一(双向)

现在我们已经将 "relationship state" 封装到一个名为 ProfessorDepartment 的实体中,我们现在可以引用 Role 实体。假设对于给定的 Professor-Department 关系只有一个角色,我们可以将其映射为一对一。

这里有一个 class 图表来说明部门、教授和角色之间的关系。

这是数据模型:

以下是每个实体的代码来说明所有的解释:

@Entity
public class College implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="COLLEGE_ID")
    private Long id;

    private String name;

    @OneToMany(mappedBy="college")
    private List<Professor> professorList = new ArrayList<Professor>(); 
...
}

@Entity
public class Professor implements Serializable {

    @Id
    @Column(name="PROF_ID")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy="professor")
    private List<ProfessorDepartment> profDepartmentList = new ArrayList<ProfessorDepartment>();

    @ManyToOne
    @JoinColumn(name="COLLEGE_ID")
    private College college;
...
}

@Entity
public class Department implements Serializable {

    @Id
    @Column(name="DEPT_ID")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy="department")
    private List<ProfessorDepartment> profDepartmentList = new ArrayList<ProfessorDepartment>();
...
}

@Entity
public class Role implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="ROLE_ID")
    private Long id;

    private String name;
...
}

@Entity
@Table(name="PROFESSOR_DEPARTMENT")
@IdClass(ProfessorDepartmentId.class)
public class ProfessorDepartment implements Serializable {

    @Id
    @ManyToOne
    @JoinColumn(name="DEPT_ID")
    private Department department;

    @Id
    @ManyToOne
    @JoinColumn(name="PROF_ID")
    private Professor professor;

    @OneToOne
    @JoinColumn(name="ROLE_ID")
    private Role role;
...
}

public class ProfessorDepartmentId implements Serializable {

    private Long department;

    private Long professor;
...
}

注意 @IdClass 注释的使用。 ProfessorDepartment 实体将有一个由 ProfessorDepartment 的主键组成的复合主键。

这是一个示例场景:

  1. 我们有教授,约翰和彼得
  2. 他们都在斯坦福大学工作
  3. 我们有3个部门:计算机部、财务部、卫生部
  4. John 在财务部担任会计
  5. Peter 在卫生部当医生
  6. John 和 Peter 都在计算机部门工作
  7. John 担任计算机管理员,而 Peter 担任支持专家 - 均在计算机部门

下面是说明该场景的代码:

    College college = new College();
    college.setName("Stanford University");

    em.persist(college);

    Professor profJohn = new Professor();
    profJohn.setCollege(college);
    profJohn.setName("John");
    college.getProfessorList().add(profJohn);

    em.persist(profJohn);

    Professor profPeter = new Professor();
    profPeter.setCollege(college);
    profPeter.setName("Peter");
    college.getProfessorList().add(profPeter);

    em.persist(profPeter);

    Department compDept = new Department();
    compDept.setName("Computer Department");

    em.persist(compDept);

    Department financeDept = new Department();
    financeDept.setName("Finance Department");

    em.persist(financeDept);

    Department healthDept = new Department();
    healthDept.setName("Health Department");

    em.persist(healthDept);

    Role accountantRole = new Role();
    accountantRole.setName("Accountant");

    em.persist(accountantRole);

    Role doctorRole = new Role();
    doctorRole.setName("Doctor");

    em.persist(doctorRole);

    Role compAdminRole = new Role();
    compAdminRole.setName("Computer Administrator");

    em.persist(compAdminRole);

    Role compSupport = new Role();
    compSupport.setName("Computer Support Specialist");

    em.persist(compSupport);

    // John works as an accountant in Finance Department
    ProfessorDepartment johnInFinanceDept = new ProfessorDepartment();
    johnInFinanceDept.setDepartment(financeDept);
    johnInFinanceDept.setProfessor(profJohn);
    johnInFinanceDept.setRole(accountantRole);
    profJohn.getProfDepartmentList().add(johnInFinanceDept);
    financeDept.getProfDepartmentList().add(johnInFinanceDept);

    em.persist(johnInFinanceDept);

    // Peter works as a doctor in Health Department
    ProfessorDepartment peterInHealthDept = new ProfessorDepartment();
    peterInHealthDept.setDepartment(healthDept);
    peterInHealthDept.setProfessor(profPeter);
    peterInHealthDept.setRole(doctorRole);
    profPeter.getProfDepartmentList().add(peterInHealthDept);
    healthDept.getProfDepartmentList().add(peterInHealthDept);

    em.persist(peterInHealthDept);

    // Both John and Peter works in Computer Department but they are of different roles
    // John works as Computer Administrator
    // Peter works as Computer Support Specialist
    ProfessorDepartment johnInCompDept = new ProfessorDepartment();
    johnInCompDept.setDepartment(compDept);
    johnInCompDept.setProfessor(profJohn);
    johnInCompDept.setRole(compAdminRole);
    profJohn.getProfDepartmentList().add(johnInCompDept);
    compDept.getProfDepartmentList().add(johnInCompDept);

    em.persist(johnInCompDept);

    ProfessorDepartment peterInCompDept = new ProfessorDepartment();
    peterInCompDept.setDepartment(compDept);
    peterInCompDept.setProfessor(profPeter);
    peterInCompDept.setRole(compSupport);
    profPeter.getProfDepartmentList().add(peterInCompDept);
    compDept.getProfDepartmentList().add(peterInCompDept);

    em.persist(peterInCompDept);

完整代码分享在我的 Github repo.