2

我有一个带有子实体列表的 JPA 实体。在这种情况下,一个附加了角色的用户实体。

它看起来(有点简化 - 省略了一些字段/方法)如下:

@Entity
public class MyUser{

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long myUserId;

 private String username; 

 @OneToMany
 @JoinTable(name = "userrole",
   joinColumns = {
     @JoinColumn(name="myUserId", unique = true)           
   },
   inverseJoinColumns = {
     @JoinColumn(name="roleId")
   }
 )
 private Collection<Role> roles;    

 public Collection<Role> getRoles() {
     return roles;
 }
}

如果感兴趣,角色实体非常简单。

@Entity
public class Role {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long roleId;
  private String role; // a few more string fields here .

当我添加两个用户和每个用户几百个角色时,当我列出用户时,我会得到一个奇怪的行为。每个用户都列出了几百次(相同的用户 = 相同的唯一 ID)。

有问题的代码:

Query q = em.createQuery("SELECT u FROM MyUser u LEFT JOIN FETCH u.roles");
Collection<MyUser> users = q.getResultList();

for(MyUser u : users){
     // print/use u here
} 

但是,当我只是访问数据库并执行 select 语句时,它似乎很好。每个用户只存在一次。

在这种情况下,我将 OpenJPA 1.2 与 IBM DB2 数据库一起使用。

4

2 回答 2

2

我认为您的模型错误,通常用户角色关系不是 OneToMany 而是“ManyToMany”,因此您应该将代码更改为如下所示:

@Entity
public class MyUser{

 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long myUserId;

 private String username; 

 @ManyToMany //This should be many to many
 @JoinTable(name = "userrole",
   joinColumns = {
     @JoinColumn(name="myUserId") //The userId in the join table should
                                  //NOT be unique because the userId can
                                  //be many times with different roles
   },
   inverseJoinColumns = {
     @JoinColumn(name="roleId")
   }
 )
 private Collection<Role> roles;    

 public Collection<Role> getRoles() {
     return roles;
 }
}

试试这个方法,看看它是否有效。

此外,您的查询不应该需要左连接,一旦您在每个实体上使用 getRoles() 方法(使用 LAZY Fetch),JPA 应该自动获取角色

于 2012-08-09T15:14:34.007 回答
1

实际上,对 User 和 UserRole 实体进行 @ManyToMany 映射是合理的。您的查询的问题是它返回连接表中的所有行,我认为您不需要这些行。因此,只需按如下方式添加group by u到您的查询中:

SELECT u FROM MyUser u LEFT JOIN FETCH u.roles GROUP BY u

你就完成了。

于 2012-08-11T04:30:07.183 回答