2

I can't work out how to check whether or not my User has a certain Role in my database. Specifically, I want to run a count query - and would like to avoid doing processing outside of the database.

Our code base uses org.springframework.data.repository.CrudRepository - and therefore we use @Query to specify queries that are complex. (org.springframework.data.jpa.repository.Query)

This SQL query returns what I would like :

SELECT Count(*) 
FROM user 
where id in (
    select user_id 
    from user_role 
    where role_type = 'ROLE_USER'
);

But I can't get a @Query to return what I would like.

Here's some code:

User class:

@Entity
@ApiModel(description = "Represents an user of the system")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "ID")
    @ApiModelProperty(value = "The ID of the user", required = true)
    private Long id;

    @Column(name = "USERNAME", unique = true)
    @ApiModelProperty(value = "The userName of the user", required = true)
    private String username;

    @Column(name = "STATUS", nullable=false)
    @Enumerated(EnumType.STRING)
    @ApiModelProperty(value = "The status of the user", required = true)
    private UserStatus status;

    @Column(name = "PASSWORD")
    @ApiModelProperty(value = "The encrypted password of the user")
    private String password;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "USER_ID", nullable=false)
    @ApiModelProperty(value = "The role of the user", required = true)
    private Set<UserRole> userRoles;
}

UserRole Class:

@Entity
public class UserRole implements Serializable {

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "ROLE_TYPE")
    @Enumerated(EnumType.STRING)
    private UserRoleType roleType;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name = "USER_ID", nullable=false, insertable=false, updatable=false)
    @ApiModelProperty(value = "The id the user (link to User table)", required = true)
    private User user;
}

And the repository Class :

//This bit doesn't work - but is here to show the intention of what I want to do!

public interface UserDao extends CrudRepository<User, Long> {    

    @Query("select count(u) from User u where u.status='ACTIVE' and u.userRoles contains 'ROLE_USER')
    public long countAllActiveUser();


}

The database is very simple containing the User table and the User_Role table.

The User table has Id, Username, Password, Status columns.

e.g.

  • 1, Dave, ****, ACTIVE
  • 2, John, ****, ACTIVE

The User_Role table has Id, Role_Type, User_Id columns.

e.g.

  • 1, ROLE_USER, 1
  • 2, ROLE_ADMIN, 1
  • 3, ROLE_USER, 2

In the above example - the answer to the count SQL is 2! (There are 2 users who are ACTIVE and has the role: ROLE_USER)

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
yeti_c
  • 135
  • 2
  • 8

1 Answers1

1

You can solve this with a simple function inside your repository interface:

long countByStatusAndUserRoles_roleType(status: UserStatus, roleType: UserRoleType)

This query should do the same:

@Query("select count(u) from User u left join u.userRoles ur where u.status = :status and ur.roleType = :roleType")
long countAllActiveUser(status: UserStatus, roleType: UserRoleType);

You can off course hardcode status and roleType.

So you first need to join the entities (tables). I chose a left join, since you need items form both entities, see here for a more detailed answer on join types. JPA joins will automatically join on the correct key, if given through the context, otherwise you get an error.

Then you can specify the conditions as usual.

Pinkie Swirl
  • 2,375
  • 1
  • 20
  • 25
  • Hi Pinkie Swirl : Thanks for this - this would solve the problem - but I need to extend this into multiple different queries that check for different parameters on this table (and a futher 'userProfile' table)... some of which may not be easy to write out in this style of function. (e.g. is a field null or empty string) Is there a solution that available using @Query instead? – yeti_c Aug 22 '18 at 01:07
  • I'm not using the ``@Query`` method, so sorry can't help there. – Pinkie Swirl Aug 22 '18 at 01:12
  • No worries - I'll +1 your response though - as it will come in handy for people trying to do similar things to me :) [PS Turns out I'm not known enough to +1 you publicly!] – yeti_c Aug 22 '18 at 01:14
  • Did you try your statement with ``@Query(nativeQuery=true)``? – Pinkie Swirl Aug 22 '18 at 01:19
  • Yeah - I've had to resort to that where I don't have an explicit mapping in the entity... but felt sure that I should be able to manage it with the Roles because I have that detail attached to the entity!! – yeti_c Aug 22 '18 at 02:14
  • Hi Pinkie Swirl, Thank you for taking the time to extend your answer to cover Query. I need to check out whether or not I'm using the correct Join. I've Ticked this response as the correct Answer :) – yeti_c Aug 22 '18 at 22:08