精简版
我有一个基本设置,其中用户表链接到角色表,角色表链接到权限。这些都是多对多关系。角色是一个动态实体,应用程序不感兴趣(仅用于视觉方面)。当我获取用户时,我想返回用户表中的数据,包括所有权限名称的列表。
为了澄清,这就是我想要解决方案做的事情:
我设法在我的用户对象中获得了权限并返回它们,但是由于在调用原始查询后 hibernate 进行了额外的查询调用,因此效率低下。
详细版
首先让我给你一些关于如何链接实体以及代码是什么样子的信息。我的(简化的)数据库表结构如下所示:
用户.java
@Entity
@Table(name = "user")
public class User {
@Id
@Column(name = "user_id", columnDefinition = "user_id")
private Long userId;
@Transient
private List<String> rights
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
@JsonIgnore
private List<Role> roles;
//Getters and setters
}
角色.java
@Entity
@Table(name = "role")
public class Role {
@Id
@Column(name = "role_id", columnDefinition = "role_id")
private Long roleId;
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"),
inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"))
@JsonIgnore
private List<Employee> employees;
@ManyToMany
@JoinTable(
name = "role_right",
joinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"),
inverseJoinColumns = @JoinColumn(name = "right_id", referencedColumnName = "right_id"))
@JsonIgnore
private List<Right> rights;
//Getters and setters
}
对.java
@Entity
@Table(name = "right")
public class Right {
@Id
@Column(name = "right_id", columnDefinition = "right_id")
private Long rightId;
@Column(name = "name", columnDefinition = "name")
private String name;
@ManyToMany
@JoinTable(
name = "role_right",
joinColumns = @JoinColumn(name = "right_id", referencedColumnName = "right_id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
@JsonIgnore
private List<Role> roles;
//Getters and setters
}
重要的是要知道我使用 Java Specifications API 来加入表格:
return (root, query, cb) -> {
query.distinct(true);
Join rolesJoin = root.join("roles", JoinType.LEFT);
Join rightsJoin = rolesJoin.join("rights", JoinType.LEFT);
return cb.conjunction();
};
这将创建正确的查询:
select <columns go here>
from employee user0_
left outer join user_role roles1_ on user0_.user_id=roles1_.user_id
left outer join role role2_ on roles1_.role_id=role2_.role_id
left outer join role_right rights3_ on role2_.role_id=rights3_.role_id
left outer join right right4_ on rights3_.right_id=right4_.right_id
到目前为止,一切对我来说都很好。但是当我尝试获取所有角色的名称时,执行了两个以上的查询(页面计数和原始查询)
//The original code uses lambda for this
for(Role role : user.getRoles()){
for(Right right: role.getRights()){
user.addRight(right.getName());
}
}
额外的查询如下所示:
select <column stuff>
from role_right rights0_
inner join right right1_ on rights0_.right_id=right1_.right_id
where rights0_.role_id=?
这使我的通话效率非常低。在这种情况下,它是单个用户,但有多个用户时会累加。
有没有办法让单个查询将所有权限的名称放在用户实体中,而不添加额外的查询执行?
到目前为止我尝试过的事情:
用于
@SecondaryTable
直接从我的用户实体中的右表定义列。我无法先将角色链接到用户,然后使用角色表中的字段来链接右表。所以最后我必须在我的 User 对象顶部添加 @SecondaryTable 注释,并在下面定义 Right 对象的列。在 User 实体中使用
@Formula
以将本机调用插入到查询中。这也不起作用,因为注释不了解如何将所有内容映射到权限列表中。
这里可能还有其他选项,或者我在实现上述选项时做了一些可怕的错误。但是现在我不知道要为我的问题找到解决方案。如果有人能告诉我,那就太好了。
在此先感谢,
罗宾