我想告诉实体自己加入一个它在两个方向上都不是唯一的字段,但看起来互联网上的所有示例都使用了连接表,或者两者都很旧。 / p>
人非规范化表:
PersonId (Pk) | RoleId | ParentRoleId
1 1 NULL
2 1 NULL
3 2 1
4 2 1
人实体(使用似乎加载空列表的映射):
@Column
private Long personId;
@Column
private Long roleId;
@Column
private Long parentRoleId;
@ManyToMany
@JoinColumn(name = "parentRoleId", referencedColumnName = "roleId", updatable = false, insertable = false)
private List<Person> personsWithParentRole;
@ManyToMany
@JoinColumn(name = "roleId", referencedColumnName = "parentRoleId", updatable = false, insertable = false)
private List<Person> personsWhoseRoleHasCurrentPersonRoleAsParent;
我想知道是否有办法映射我的案例。我知道它不是最好的拱形或性能最好的,并且可以使用不同的方法,但是我只是想知道那个特定的解决方案。这是对最复杂案例的简化。
答案 0 :(得分:1)
我认为在你的案例中避免连接表绝对是一个坏主意。您当前的解决方案是最好的。
我认为你需要这样的东西:
public class Person {
@Id
private long id;
@JoinTable(name = "person_links", joinColumns = {
@JoinColumn(name = "subordinate", referencedColumnName = "id", nullable = false)}, inverseJoinColumns = {
@JoinColumn(name = "manager", referencedColumnName = "id", nullable = false)})
@ManyToMany
private List<Person>subordinates;
@ManyToMany(mappedBy = "subordinates")
private List<Person> managers;
}
答案 1 :(得分:1)
免责声明:这个答案不是确定的。我为可读性写了答案,并且要在OP的评论中进行改进。此外,代码未经过测试。
作为答案,我将避免连接表并假设该表的设计如下:
person
和role
,各主键列PersonId
和RoleId
RoleId
和ParentRoleId
是引用相同role.RoleId
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 | 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]
/!\小心初始化的东西(懒惰初始化可能很棘手)/!\
希望这有帮助