我有一个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;
}
}
如果是intressting,则Role实体非常简单。
@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数据库一起使用。
答案 0 :(得分:1)
我认为你的模型有问题,通常用户角色关系不是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应自动获取角色
答案 1 :(得分:1)
实际上,为User和UserRole实体提供@ManyToMany映射是合理的。您的查询的问题是它返回连接表中我认为您不需要的所有行。因此,只需在查询中添加group by u
,如下所示:
SELECT u FROM MyUser u LEFT JOIN FETCH u.roles GROUP BY u
你会完成的。