如何在JpaRepository

时间:2018-02-04 16:14:28

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

我有这样的数据库结构:

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

我想获得用户有权访问的所有评论。

为我提供访问权限意味着(当我创建post对象时,我自动创建名为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<>();  

用户和user_role表:

@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<>();

这是评论表:

@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); 

如果我没错,它会打印该特定用户创建的评论。

那么我真正想要实现的目标是什么?让我在示例数据上向您展示:

作用:

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

在帖子中注释名称为cd:

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

帖子中的评论名称为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”字符串,此解决方案将打印所有注释。

所以如果我有role_postName1和role_postName2 它打印:

comment1FromPost1
comment2FromPost1
comment1FromPost2
comment2FromPost2
comment1FromPost1
comment2FromPost1
comment1FromPost2
comment2FromPost2

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

2 个答案:

答案 0 :(得分:1)

@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);

答案 1 :(得分:0)

请在您的问题中更具体。

如果我理解正确 - 您希望按用户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);

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