2011-10-27 83 views
1

我一直卡在實體和字符串之間的M:N關係中。用戶可以有多個角色,每個角色可以分配給多個用戶。角色只是一個字符串。表中包含兩列角色:roleIdroleName獲取包含其他熱切收集的實體的熱切收集

我創建了兩個實體,但我完全無法使它工作。第一實體的用戶:

@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根本不會獲取子集合。它從與表UsersToRoles加入的用戶表中選擇,但缺少表userRoles的加入。

我可以這樣做嗎?我能否熱切地收集包含另一個熱切獲取的集合的實體?

回答

1

你的映射是完全錯誤的。 UsersToRoles有一個roleId列。因此它是指一個角色。它怎麼可能有一組角色名稱?登錄列在實體中映射兩次。而且,對於我來說,這看起來像是一個簡單的連接表,沒有除roleId和login之外的任何其他屬性,它們分別是User和Role的ID的外鍵。

您應該有兩個實體:UserRole,使用關聯使用UsersToRoles表作爲聯接表。而已。 UsersToRoles表不應該被映射爲一個實體:它是一個純粹的連接表。

1

JPA提供程序通常具有表示默認提前獲取深度的配置屬性,即Hibernate的hibernate.max_fetch_depth。檢查增加時是否可以看到更多。

另外,想想你的設計。只有在有限的情況下(性能方面),熱切獲取集合的子集合可能是一個好主意。當你像這樣註解你的實體時,你將會在所有用例中使用預先抓取。也許你會比懶惰更好,只用一個帶有JOIN FETCH子句的查詢來明確地獲取它?