如何在JPQL中查询一对多关系?

时间:2013-12-11 14:06:06

标签: jpa jpql

有一个用户实体与角色实体有一对多的关系。换句话说,一个用户可以拥有多个角色。无论如何,当我使用JPQL查询时,Role实体显示重复的结果,在这种情况下,它显示ROLE_ADMIN两次。当我调试代码时,我可以看到Role实体具有相同的内存ID:

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

我不确定我是否在JPQL中做错了什么。如果我错了,请纠正我。以下是这个问题的一些提示。


这是Users表中提供的内容:

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

这是Users表的表格描述:

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

这是授权表中可用的内容:

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

这是授权表的表格描述:

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

这是关于用户实体的查询:

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

这是角色实体:

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

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

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

这是我检索结果的方法:

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

1 个答案:

答案 0 :(得分:1)

  • 目前尚不清楚您要通过此查询尝试实现的目标。如果您希望按username加载用户,并且username是主键,则可以按以下方式执行:

    User u = em.find(User.class, username);
    
  • 您的Role实体映射不正确导致结果不正确:userId注释为@Id,但它不是主键(即它不是唯一的)。< / p>

我建议你改变数据库架构。 UserRole(带连接表)之间的多对多关系将更容易映射:

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

public class Role {
    @Id 
    private String authority;
}

如果修复了当前的数据库架构,则需要:

  • 使用authority
  • 表达username具有复合键(authority@EmbeddedId)的事实
  • 让你的关系双向
  • 使用@MapsId表示外键authorityusername)是authority
  • 的复合键的一部分

另见: