【问题标题】:how to construct spring JPA/JPQL query in JpaRepository如何在 JpaRepository 中构造 Spring JPA/JPQL 查询
【发布时间】:2018-07-14 13:56:00
【问题描述】:

我有一个这样的数据库结构:

topics 1:n posts  1:n comments and users n:n roles.

我想获取该用户有权访问的所有 cmets。

为我授予访问权限意味着(当我创建帖子对象时,我会自动创建名为 PostName 的角色对象,前缀为 role_comment_ 例如,名为 abc 的帖子具有名为:role_comment_abc 的角色)

现在我尝试创建如下的 jpa/jpql 查询:

find all comments by User where user_id is =:1 and role_name contaings =:2
findByUserIdAndRoleNameContaining(Integer userId, String roleName);

这是我的用户、角色和评论表的样子:

角色表:

@Entity
@Table(name = "roles")
public class Role {

    @Id
    private Integer id;
    private String name;

    @ManyToMany(mappedBy = "roles")
    private Set<User> users = new HashSet<>();  

用户和用户角色表:

@Entity
@Table(name = "users")
public class User {

@Id
private Integer id;
private String name;

@ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
@JoinTable(
        name = "user_role",
        joinColumns = { @JoinColumn(name = "user_id") },
        inverseJoinColumns = { @JoinColumn(name = "role_id") }
)
private Set<Role> roles = new HashSet<>();

这是 cmets 表:

@Entity
@Table(name = "comments")
public class Comments{

@Id
private Integer id;
private String name;
private String description;

@ManyToOne(optional = false)
@JoinColumn(nullable = false, name = "user_id")
private User user

不幸的是,如果我在 JpaRepository 中创建名为:

List<Comments> findByUserId(Integer id); 

如果我没记错的话,它将打印由该特定用户创建的 cmets。

那么我真正想要达到的目标是什么?让我通过示例数据向您展示这一点:

角色:

100;"role_comment_ab"
101;"role_comment_cd"
102;"role_comment_ef"
103;"something_else"

以 ab 为名的帖子中的评论:

1;"Test1";"Test description";10
2;"Test2";"Test description";10

cmets 在帖子中名为 cd:

3;"Test3";"Test description";10
4;"Test4";"Test description";10

cmets 在帖子中名为 ef:

5;"Test5";"Test description";10
6;"Test6";"Test description";10

用户:

10;"Thomas" (logged user)
11;"John"

users_roles:

10;100
11;101
10;102
10;103

输入:

findByUserIdAndRoleNameContaining(10, "role_comment_");

输出:

   1;"Test1";"Test description";10
   2;"Test2";"Test description";10
   5;"Test5";"Test description";10
   6;"Test6";"Test description";10

我真的不知道我的查询应该是什么样子。请至少给我一个小提示。

更新: 添加@Bohdan Petrenko 解决方案后:

@Query("select c from Comment c join c.user u join u.roles r where u.id = :userId and lower(r.name) like lower(:roleName)")
List<Comment>  findByUserIdAndRoleNameContaining(@Param("userId") Integer userId, @Param("roleName") String roleName);

roleName = "%" + roleName.trim() + "%";

我注意到如果@Param roleName 包含“roleName”字符串,此解决方案将打印所有 cmets。

如果我有 role_postName1 和 role_postName2 它打印:

comment1FromPost1
comment2FromPost1
comment1FromPost2
comment2FromPost2
comment1FromPost1
comment2FromPost1
comment1FromPost2
comment2FromPost2

只有当用户具有名为 role_postName 的角色时,才能找到从帖子中打印 cmets 的解决方案。

【问题讨论】:

  • 你试过findByUser_IdAndUser_Roles_Name(Integer userId, String roleName)
  • 您的解决方案给了我一个错误:调用 init 方法失败;嵌套异常是 java.lang.IllegalStateException:非法尝试取消引用基本类型的路径源 [null.user.roles]
  • @pvpkiran 你知道为什么会出现这个问题吗?
  • 因为角色是一个集合。我认为您需要使用元素并查看该角色是否存在于该用户的角色集中。在这里查看我的答案stackoverflow.com/questions/48424575/…

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


【解决方案1】:

请在您的问题中更具体。

如果我理解正确 - 您想按用户 ID 和角色名称选择主题。如果是,你可以尝试这样的事情:

@Query("select t from Topic t join t.user u join u.roles r where u.id = :userId and lower(r.name) like lower(:roleName)")
List<Topic>  findByUserIdAndRoleNameContaining(@Param("userId") Integer userId, @Param("roleName") roleName);

但是在将角色名称传递给存储库方法findByUserIdAndRoleNameContaining之前,您还需要更改角色名称:

roleName = "%" + roleName.trim() + "%";

更新

这无需任何自定义 SQL 和 roleName 修改即可工作

List<Comment> findByUser_IdAndUser_Roles_NameContainingIgnoreCase(Integer userId, String roleName);

而且我也不明白你现在面临的麻烦。因此,为我们提供一些带有测试数据的示例(来自数据库),查询的正确和不正确的预期结果。由于我不明白您的问题的原因,我无法帮助您解决它。

【讨论】:

  • 对不起,我在一个问题中犯了一个小错误。我想选择评论(不是主题),但这将是类似的事情。 :) 请给我一秒钟来检查您的解决方案 :)
  • 是的,当然。没问题。但是看看@pvpkiran 的回答。它更短更干净。
  • 您的解决方案有问题。 (这可能是因为误解了我的问题)。让我为你更新我的问题。
  • 我想做的是:仅当用户具有名为 role_postName 的角色时才从帖子中获取所有 cmets。但用户甚至可以拥有 10 个角色。
  • 那么,您根本不想指定用户 ID?只有角色名?或者你想让用户 id 可选并且只在它存在时指定?
【解决方案2】:
@Query("select t from Topic t 
        join t.user u 
        where u.id = :userId 
        and u.roles in :roleNames")
List<Topic>  findByUserIdAndRoleNameContainedIn(@Param("userId") Integer userId, @Param("roleNames") List<String> roleNames);

【讨论】:

    猜你喜欢
    • 2017-11-30
    • 2017-11-28
    • 2017-09-06
    • 1970-01-01
    • 2021-08-21
    • 2019-10-27
    • 1970-01-01
    • 2019-05-03
    • 2017-11-19
    相关资源
    最近更新 更多