【问题标题】:JPQL query to fetch all roles of user based on user idJPQL 查询根据用户 ID 获取用户的所有角色
【发布时间】:2021-02-01 08:04:39
【问题描述】:

在我的项目中,用户和角色之间存在多对多关系。出于这个原因,我还有新实体 UserRole 连接这两个实体。

看起来像这样:

用户:

@Data
@Entity
@Table(NAME = "USERS")
public class User {
    @Id
    @Column(name = "USER_ID")
    private String userId;
    @Basic
    @Column(name = "EMAIL")
    private String email;
   
    @OneToMany(fetch = LAZY, mappedBy = "user")
    private Set<UserRole> userRoles;
}

角色:

@Data
@Entity
@Table(NAME = "ROLES")
public class Role {
    @Id
    @Column(name = "ROLE_ID")
    private String roleId;
    @Basic
    @Column(name = "NAME")
    private String name;
   
    @OneToMany(fetch = LAZY, mappedBy = "role")
    private Set<UserRole> userRoles;
}

用户角色:

@Data
@Entity
@IdClass(UserRolePK.class)
@Table(NAME = "USER_ROLES")
public class UserRole {
    @Id
    @Column(name = "USER_ID")
    private String userId; 

    @Id
    @Column(name = "ROLE_ID")
    private String roleId;
    
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "USER_ID", insertable = false, updatable = false)
    private User user;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "ROLE_ID", insertable = false, updatable = false)
    private Role role;
}

在这种情况下,用户可以拥有多个角色。

问题:如何使用一个查询 (JPQL) 通过他的 id (userId) 获取所有分配给他的角色的用户?

我知道我可以先通过 id 获取用户,然后我可以根据 UserRole 表单独获取角色。

但我想在一个查询中做到这一点。我想要拥有角色列表的用户。

【问题讨论】:

  • 你真的需要中间表UserRole 来实现UserRole 之间的ManyToMany 关系吗?您还遇到了映射问题:您对User.userRolesRole.userRoles 使用相同的mappedBy = "user"
  • @SternK 不幸的是我需要这张表,它是由其他人在数据库中创建的,我无法更改它。我会修复我的映射谢谢。

标签: java spring spring-data-jpa jpql hibernate-mapping


【解决方案1】:

您可以使用fetch 关键字:

@Query(
    "select u " +
    "from User u " +
    "left join fetch u.userRoles "+
    "where u.userId = :id "
)
List<User> getUsersByIdAndRoles(@Param("id") String id)

【讨论】:

  • 但我只想根据 userId 获取用户和他的角色列表
  • 在这种情况下,我将拥有具有 UserRoles 列表的用户,但我无权访问角色,因为我将此集合设置为延迟获取。
  • @Rocky3582 您将拥有访问权限。这就是fetch 的含义……
  • 此查询将获取具有 UserRoles 列表的用户。在 UserRoles 中,我只能访问 roleId,但我想访问 Role 对象中的角色名称。使用此查询我无权访问 Role 对象,因为它会抛出 LazyInitException
【解决方案2】:

我建议您通过以下方式更正您的映射:

@Data
@Entity
@Table(NAME = "USERS")
public class User {
    @Id
    @Column(name = "USER_ID")
    private String userId;

    @Column(name = "EMAIL")
    private String email;
   
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "USER_ROLES",
              joinColumns = @JoinColumn(name = "USER_ID"),
              inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
    private Set<Role> roles;
}

@Data
@Entity
@Table(NAME = "ROLES")
public class Role {
    @Id
    @Column(name = "ROLE_ID")
    private String roleId;

    @Column(name = "NAME")
    private String name;
   
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "roles")
    private Set<User> users;
}

此更正不会影响仅休眠映射的数据库架构。 然后您将能够按照 Andronicus 答案中的建议进行操作:

@Query(
    "select u " +
    "from User u " +
    "left join fetch u.roles "+
    "where u.userId = :id "
)
List<User> getUsersWithFetchedRoles(@Param("id") String id)

如果您继续使用当前映射,您将无法一次获取多个关联,如 this 文章中所述。

有关@ManyToMany 关联的其他详细信息,请参阅documentation

【讨论】:

    猜你喜欢
    • 2019-06-16
    • 2014-10-22
    • 2018-08-20
    • 2023-03-21
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2021-10-06
    相关资源
    最近更新 更多