1

エンティティと文字列の間の M:N 関係に行き詰まっています。ユーザーは複数の役割を持つことができ、各役割を複数のユーザーに割り当てることができます。Role は単なる文字列です。役割は、 と の 2 つの列を持つテーブルに含まれていroleIdますroleName

2 つのエンティティを作成しましたが、まったく機能しません。最初のエンティティはユーザーです:

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

2 つ目は、接続テーブルに関連付けられたエンティティです。

@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コレクションが常に null であることです。私はそれを働かせることができません。@CollectionTable注釈のテーブル名を間違えても、まだ機能します。JPA はサブコレクションをまったくフェッチしません。table に結合されたユーザーのテーブルから選択しますが、テーブルUsersToRolesへの結合がuserRolesありません。

私はそれをすることができますか?別の熱心にフェッチされたコレクションを含むエンティティの熱心なコレクションを取得できますか?

4

2 に答える 2

1

あなたのマッピングは完全に間違っています。UsersToRolesコラムがありroleIdます。したがって、それは単一の役割を指します。ロール名のコレクションをどのように持つことができますか? ログイン列は、エンティティで 2 回マップされます。さらに、これは単純な結合テーブルのように見えますが、それぞれ User と Role の ID への外部キーである roleId と login 以外の属性はありません。

テーブルを結合テーブルとして使用する関連付けで、 と のUser2つのエンティティが必要です。それでおしまい。UsersToRoles テーブルはエンティティとしてマップしないでください。これは純粋な結合テーブルです。RoleManyToManyUsersToRoles

于 2011-10-27T15:29:45.770 に答える
1

hibernate.max_fetch_depth通常、JPA プロバイダーには、デフォルトの熱心なフェッチの深さ (つまりHibernate 用) を示す構成プロパティがあります。大きくするともっと見えるか確認してください。

また、あなたのデザインについて考えてください。コレクションのサブコレクションを熱心に取得することは、限られたシナリオでのみ (パフォーマンスの観点から) 良い考えかもしれません。そのようにエンティティにアノテーションを付けると、すべてのユースケースで熱心なフェッチを使用することになります。おそらく、JOIN FETCH句を使用したクエリを使用して、「怠惰」で明示的にのみ熱心にフェッチした方がよいでしょうか?

于 2011-10-27T14:54:41.390 に答える