熱心に収集された他のエンティティを熱心に収集する

私はエンティティと文字列の間のM:Nの関係に固執しています。ユーザーは複数のロールを持つことができ、各ロールは複数のユーザーに割り当てることができます。役割は単なる文字列です。ロールは、 roleIdroleName の2つの列を含む表に含まれています。

私は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 roles;
    @Transient
    private Collection roleNames;

    public String getLogin() {
        return login;
    }

    public String getPassword() {
        return password;
    }

    @PostLoad
    void prepareRoleNames() {
        roleNames = new HashSet(roles.size());
        for (UsersToRoles mapping : roles)
            roleNames.add(mapping.getNameOfRole());
    }

    public Collection 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 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はサブコレクションをまったくフェッチしません。テーブル UsersToRoles でジョインされたユーザーのテーブルから選択しますが、テーブル userRoles へのジョインはありません。

私はこれを行うことはできますか?熱心に取り込まれた別のコレクションを含むエンティティを熱心に収集できますか?

1

2 答え

あなたのマッピングは完全に間違っています。 UsersToRoles には roleId という列があります。したがって、それは単一の役割を指しています。どのようにしてロール名の集合を持つことができますか?ログイン列はエンティティ内で2回マップされます。さらに、これは、ユーザーとロールのIDに対する外部キーであるroleIdおよびlogin以外の属性を使用せずに、私にとって単純な結合テーブルのように見えます。

UsersRole という2つのエンティティがあり、 ManyToMany の関連付けは UsersToRoles テーブルを結合テーブルとして使用します。それでおしまい。 UsersToRolesテーブルをエンティティとしてマッピングする必要はありません。純粋な結合テーブルです。

1
追加された

JPAプロバイダは、通常、Hibernateのデフォルトのeager fetch depth、つまり hibernate.max_fetch_depth を示す構成プロパティを持っています。あなたがそれを増やすときにもっと見ることができるかどうかを確認してください。

また、あなたのデザインについて考えてみてください。コレクションのサブコレクションを熱心に取得することは、限られたシナリオ(パフォーマンス上)でのみ有効な考えです。そのようなエンティティに注釈を付けると、すべてのユースケースでeagerフェッチを使用することになります。おそらく、 "lazy"を使って、JOIN FETCH節を持つクエリを使って、明示的にのみ熱心にそれを取得する方が良いでしょうか?

1
追加された