gpt4 book ai didi

java - Spring + Hibernate : How do I efficiently chain two link tables and include resulting data in single entity?(用户角色权限)

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:15:20 25 4
gpt4 key购买 nike

精简版

我有一个基本设置,其中用户表链接到角色表,角色表链接到权限。这些都是多对多关系。角色是一个动态实体,应用程序不感兴趣(仅针对视觉方面)。当我获取用户时,我想返回用户表中的数据,包括所有权限的名称列表。

澄清一下,这就是我希望解决方案执行的操作:

solution overview

我设法在我的用户对象中获得权限并返回它们,但由于在调用原始查询后 hibernate 进行了额外的查询调用,所以效率很低。

详细版

首先让我向您介绍一些有关实体如何链接以及代码是什么样子的信息。我的(简化的)数据库表结构如下所示:

Database diagram

用户.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
}

Right.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 规范 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 对象的列。

  • 在用户实体中使用 @Formula 将 native 调用插入到查询中。这也不起作用,因为注释不理解如何将所有内容映射到权限列表中。

这里可能还有其他选项,或者我在实现上述选项时犯了严重错误。但是现在我不知道该用什么方法来解决我的问题。如果有人能告诉我,那就太好了。

提前致谢,
罗宾

最佳答案

您正在使用 Root.join它只是为了查询的目的而连接表;加载实体中的惰性关联仍然不会被初始化。

如我所见,您的意图也是初始化惰性集合。为此你必须使用 Root.fetch (在继承自FetchParent的接口(interface)方法中定义):

Create a fetch join to the specified collection-valued attribute using the given join type.

但是,您的意图并不是一个好的做法;不要在一个查询中连接多个集合,否则查询结果集将在连接的集合之间以完整的笛卡尔积爆炸。您的结果集包含 <num of users> * <num of roles per user> * <num of rights per role>行。所以,每个用户数据都是重复<num of roles per user> * <num of rights per role>生成结果集中的次数。

我发现最好和最直接的方法是指定 batch size关于惰性关联。

关于java - Spring + Hibernate : How do I efficiently chain two link tables and include resulting data in single entity?(用户角色权限),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36714140/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com