我被实体和字符串之间的M:N关系卡住了。一个用户可以有多个角色,每个角色可以分配给多个用户。Role只是一个字符串。角色包含在包含两列的表中:roleId和roleName。
我已经创建了两个实体,但我完全无法使其工作。第一个实体是用户:
@Entity
@Table(name="appUsers")
public class UserEntity {
@Id
private String login;
private String password;
@OneToMany(fetch=FetchType.EAGER,mappedBy="user") //we always need to load user's roles
private Collection<UsersToRoles> roles;
@Transient
private Collection<String> roleNames;
public String getLogin() {
return login;
}
public String getPassword() {
return password;
}
@PostLoad
void prepareRoleNames() {
roleNames = new HashSet<String>(roles.size());
for (UsersToRoles mapping : roles)
roleNames.add(mapping.getNameOfRole());
}
public Collection<String> getRoles() {
return roleNames;
}
}第二个是与连接表关联的实体:
@Entity
@IdClass(UsersToRolesId.class)
public class UsersToRoles {
@Id
@SuppressWarnings("unused")
@Column(name="login")
private String login;
@Id
@SuppressWarnings("unused")
@Column(name="roleId")
private int roleId;
@ElementCollection(fetch=FetchType.EAGER)
@CollectionTable(name="userRoles", joinColumns={@JoinColumn(name="roleId")})
private List<String> roleName;
@ManyToOne
@JoinColumn(name="login")
@SuppressWarnings("unused")
private UserEntity user;
public String getNameOfRole() {
if (roleName.isEmpty())
throw new CommonError("Role name for roleId=" + roleId, AppErrors.ACCESSOR_UNAVAILABLE);
return roleName.get(0);
}
}
class UsersToRolesId {
private String login;
private int roleId;
/**
* Implicit constructor is not public. We have to
* declare public non-parametric constructor manually.
*/
public UsersToRolesId() {
}
@Override
public int hashCode() {
return 17*login.hashCode() + 37*roleId;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof UsersToRolesId))
return false;
UsersToRolesId ref = (UsersToRolesId)obj;
return (this.login.equals(ref.login) && this.roleId == ref.roleId);
}
}问题是,roleName集合始终为空。我不能让它工作。当我在@CollectionTable注释中的表名中出现错误时,它仍然可以工作。JPA根本不读取子集合。它使select from user表与表UsersToRoles联接,但缺少到表userRoles的联接。
我能做到吗?我能得到一个包含另一个被急切获取的集合的实体集合吗?
发布于 2011-10-27 23:29:46
你的映射是完全错误的。UsersToRoles有一个roleId列。因此,它指的是单个角色。它怎么会有角色名称的集合呢?login列在实体中映射两次。此外,对我来说,这看起来像一个简单的连接表,除了roleId和login之外没有任何其他属性,这两个属性分别是用户和角色ID的外键。
您应该有两个实体:User和Role,以及一个使用ManyToMany表作为连接表的UsersToRoles关联。就这样。UsersToRoles表不应该映射为实体:它是一个纯连接表。
发布于 2011-10-27 22:54:41
JPA提供者通常有一个配置属性来表示默认的即时获取深度,即Hibernate的hibernate.max_fetch_depth。当您增加它时,请检查是否可以看到更多内容。
另外,考虑一下你的设计。只有在有限的情况下(性能方面),急切地获取集合的子集可能是一个好主意。当你像那样注释你的实体时,你将在所有的用例中使用急切抓取。也许使用"lazy“会更好,并且只需要显式地使用带有JOIN FETCH子句的查询来获取它?
https://stackoverflow.com/questions/7916689
复制相似问题