免责声明:这个答案不是确定的。为了便于阅读,我写了答案,它的目的是随着 OP 的评论进行改进。此外,代码没有经过测试。
数据库设计
对于答案,我将避免 join table 并假设该表的设计如下:
- 有两个表:
person 和 role,主键列分别为 PersonId 和 RoleId
- 在person表中,
RoleId和ParentRoleId是指同一个role.RoleId的外键
-
role 表中的其他列(例如角色之间的关系)与问题无关
JPA
实体
实体遵循表结构。 Role 实体将是一个基本实体:
@Entity
public class Role{
// ---- JPA attributes
@Id
// ...
@Column(...)
private Long roleId;
@OneToMany(mappedBy = "role")
private List<Person> personsWithThisRoleAsPrimaryRole;
@OneToMany(mappedBy = "parentRole")
private List<Person> personsWithThisRoleAsParentRole;
// ---- Constructor
public Role(){
// your initialisation
// initialise list to avoid NullPointerException
this.personsWithThisRoleAsPrimaryRole = new ArrayList<>();
this.personsWithThisRoleAsParentRole = new ArrayList<>();
}
// getters & setters
}
绕过连接表的技巧是利用 @OneToMany 关系和瞬态属性:
@Entity
public class Person{
// ---- JPA attributes
@Id
// ...
@Column(...)
private Long personId;
@ManyToOne
@JoinColumn(name = "RoleId")
private Role role;
@ManyToOne
@JoinColumn(name = "ParentRoleId")
private Role parentRole;
// ---- Transient attributes
@Transient
private List<Person> personsWithParentRole;
@Transient
private List<Person> personsWhoseRoleHasCurrentPersonRoleAsParent;
// ---- Constructor
public Person(){
// your initialisation
// initialise list to avoid NullPointerException
this.personsWithParentRole = new ArrayList<>();
this.personsWhoseRoleHasCurrentPersonRoleAsParent = new ArrayList<>();
}
@PostLoad
public void postLoad(){
// during JPA initialisation, role and parentRole have been defined
// if the value exist in the database. Consequently, we can fetch some
// interesting info:
if(role != null){
personsWithParentRole.addAll(role.getPersonsWithThisRoleAsParentRole());
}
if(parentRole != null){
personsWhoseRoleHasCurrentPersonRoleAsParent.addAll(parentRole.getPersonsWithThisRoleAsPrimaryRole());
}
}
// getters and setters for JPA attributes
// getters for transient attributes. It doesn't make sense to create the setters for the transient list here.
}
瞬态属性
瞬态属性必须小心使用,因为我遇到了许多奇特的问题。但是,它们很有用,因为您可以一次获取人员列表。如果你有类似的东西:
public List<Person> getPersonsWithParentRole{
if(role != null){
return role.getPersonsWithThisRoleAsParentRole();
}
}
public List<Person> getPersonsWithParentRole{
if(parentRole != null){
return parentRole.getPersonsWithThisRoleAsPrimaryRole();
}
}
它也应该可以工作,但在性能方面,它可能会产生额外的不相关计算。
举个例子
要看看它是否应该工作,让我们像草稿一样用纸+笔:
人员表
Person | Role | ParentRoleId
------ | ---- | ------------
1 | 1 | null
2 | 1 | null
3 | 2 | 1
4 | 2 | 1
角色表
Role | Additional Columns
---- | ----------------
1 | ...
2 | ...
实体方面
不考虑@PostLoad 和临时列表的Person 实体:
Person | Role | ParentRoleId
------ | ---- | ------------
1 | 1 | null
2 | 1 | null
3 | 2 | 1
4 | 2 | 1
具有@OneToMany 关系的角色实体:
Role | PersonsWithThisRoleAsPrimaryRole | PersonsWithThisRoleAsParentRole
---- | -------------------------------- | -------------------------------
1 | [1, 2] | [3, 4]
2 | [3, 4] | [empty]
因此,在@postLoad 之后,您将拥有:
Person | Role | ParentRoleId | PersonsWithParentRole | PersonsWhoseRoleHasCurrentPersonRoleAsParent
------ | ---- | ------------ | --------------------- | --------------------------------------------
1 | 1 | null | [3,4] | [empty]
2 | 1 | null | [3,4] | [empty]
3 | 2 | 1 | [empty] | [1, 2]
4 | 2 | 1 | [empty] | [1, 2]
/!\ 注意初始化的东西(延迟初始化可能很棘手)/!\
希望对你有帮助