Pregunta

There is a user entity having one-to-many relationship with role entity. In other words, one user can have multiple roles. Anyhow when I query using JPQL, the Role entity is showing duplicate results, in this case, it shows ROLE_ADMIN twice. When I debug the code, I can see that the Role entity is having same memory id:

[org.huahsin.Role@1b332d22, org.huahsin.Role@1b332d22]

I wasn't sure whether I have did something wrong in JPQL. Please correct me if I'm wrong. The following are some hints on this problem.


This is the content available in Users table:

+----------+----------+---------+
| username | password | enabled |
+----------+----------+---------+
| user7    | user7    |       1 |
+----------+----------+---------+

This is the table description for Users table:

+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| username | varchar(10) | NO   | PRI |         |       |
| password | varchar(32) | YES  |     | NULL    |       |
| enabled  | int(11)     | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+

This is the content available in Authority table:

+----------+------------+
| username | authority  |
+----------+------------+
| user7    | ROLE_ADMIN |
| user7    | ROLE_USER  |
+----------+------------+

This is the table description for Authority table:

+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| username  | varchar(10) | NO   | MUL | NULL    |       |
| authority | varchar(10) | NO   |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+

This is the query on User entity:

@NamedQuery(
        name="findByUser",
        query="select u from User u where u.username in (select r.userId from u.roleList r where r.userId = :username)")
@Entity
@Table(name="users")
public class User {

    @Id
    private String username;

    private String password;

    private Integer enabled;

    @OneToMany(targetEntity = Role.class, cascade = {CascadeType.ALL})
    @JoinColumn(name="username")
    private List<Role> roleList;

This is the Role Entity:

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

    @Id
    @Column(name="username")
    private String userId;

    @Column(name="authority")
    private String role;

This is how I retrieve the results:

List<User> l = emf.createEntityManager().createNamedQuery("findByUser", User.class).setParameter("username", username).getResultList();
for( User u : l ) {
    System.out.println(u.getUsername());
    System.out.println(u.getRoleList());
}
¿Fue útil?

Solución

  • It's not clear what you are trying to achieve by this query. If you want to load a user by its username, and username is a primary key, you can do it as follows:

    User u = em.find(User.class, username);
    
  • You get incorrect results because your Role entity is mapped incorrectly: userId is annotated as @Id, but it's not a primary key (i.e. it's not unique).

I'd suggest you to change the database schema. A many-to-many relationship between User and Role (with join table) would be much easier to map:

public class User {
    ...
    @OneToMany
    @JoinTable(name = "users_authority")
    private List<Role> roleList;
    ...
}

public class Role {
    @Id 
    private String authority;
}

If the current database schema is fixed, you'll need to:

  • Express the fact that authority has composite key (username, authority) using @EmbeddedId
  • Make your relationship bidirectional
  • Use @MapsId to indicate the fact that foreign key authority(username) is a part of the composite key of authority

See also:

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top