6

MySQL データベースにテーブルがあります。残念ながら、GlassFish Server での JAAS 認証/承認に必要な複合主キーがあります。

mysql> desc group_table;
+---------------+--------------+------+-----+---------+-------+
| Field         | Type         | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+-------+
| user_group_id | varchar(176) | NO   | PRI | NULL    |       |
| group_id      | varchar(15)  | NO   | PRI | NULL    |       |
+---------------+--------------+------+-----+---------+-------+
2 rows in set (0.05 sec)

テーブルには、次の形式のデータが含まれています。

mysql> select * from group_table;
+-------------------------+------------+
| user_group_id           | group_id   |
+-------------------------+------------+
| you123@gmail.com        | ROLE_ADMIN |
| you123@gmail.com        | ROLE_USER  |
| you123@ymail.com        | ROLE_USER  |
| you123@hotmail.com      | ROLE_USER  |
| you123@yahoo.com        | ROLE_USER  |
+-------------------------+------------+
5 rows in set (0.00 sec)

が に設定されている場合、 は正常に動作<p:dataTable>します。rowKeylazyfalse

<p:dataTable rowKey="#{row.groupTablePK.userGroupId} #{row.groupTablePK.groupId}">
    ...
</p:dataTable>

GroupTablePK@Embeddableクラス(JPA)です。このクラスの詳細は必要ないと思います。


lazyただし、 で が有効になっている場合は<p:dataTable>getRowKey()およびgetRowData()メソッドを実装する必要があります。

行キー (一意の行識別子) として列の組み合わせを必要とする複合主キーがある場合、これを行うにはどうすればよいでしょうか?

@Named
@ViewScoped
public class UserAuthorityManagedBean extends LazyDataModel<GroupTable> implements Serializable {

    private static final long serialVersionUID = 1L;

    @Override
    public Object getRowKey(GroupTable groupTable) {
        return groupTable != null ? groupTable.getGroupTablePK() : null;
    }

    @Override
    public GroupTable getRowData(String rowKey) {
        List<GroupTable> list = (List<GroupTable>) getWrappedData();

        System.out.println("rowKey : " + rowKey);
    }

    @Override
    public List<GroupTable> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) {
        //... setRowCount(rowCount);
        //... Return a List<GroupTable> from a business Service.
    }
}

上記の実装は不完全なままです。

<p:dataTable>これらの実装で行が選択されると、メソッドsout内のステートメントgetRowData()は次のように表示します。

Info:  rowKey : entity.GroupTablePK[ userGroupId=you123@gmail.com
Info:  rowKey : groupId=ROLE_USER ]

このgetRowKey()メソッドは のインスタンスを返しますが、GroupTablePKこのメソッドgetRowData()は文字列型のパラメーターしか受け入れません。これは、複合主キー (ここでは ) を表すオブジェクトではないGroupTablePKため、適切なオブジェクト型 ( GroupTablePK) に型変換できます。これに基づいてGroupTable、指定された から のインスタンスを取得し、そのインスタンスを返すメソッドをList<GroupTable>取得できます。 .getRowData()GroupTable

さらに進めるには?


質問は純粋に直前の質問に基づいています:

java.lang.UnsupportedOperationException: getRowData(String rowKey) は、基本的な rowKey アルゴリズムが使用されていない場合に実装する必要があります


編集:

に加えてhashcode()と の実装equals()があります。のメソッドは返されますが、 a の行が選択されたときにメソッドが 2 回呼び出されます。後続の 2 つの呼び出しでの文字列表現を 2 つの部分で返します。最初の呼び出しでは が返され、2 回目の呼び出しでは が返されます。toString()GroupTablePKtoString()GroupTablePKreturn "entity.GroupTablePK[ userGroupId=" + userGroupId + ", groupId=" + groupId + " ]";getRowData()<p:dataTable>GroupTablePKentity.GroupTablePK[ userGroupId=aaagroupId=ROLE_USER ]

entity.GroupTablePK[ userGroupId=aaa, groupId=ROLE_USER ]代わりに、1 回の呼び出しで一度に返す必要があります。

したがって、この種の比較groupTable.getGroupTablePK().toString().equals(rowKey)は不可能であり、この投稿の前に考えていました。そのような、

@Override
public GroupTable getRowData(String rowKey) {
    List<GroupTable> list = (List<GroupTable>) getWrappedData();

    for (GroupTable groupTable : list) {
        if (groupTable.getGroupTablePK().toString().equals(rowKey)) {
            return groupTable;
        }
    }

    return null;
}

編集2:

以下は、JPA ノイズを除去して問題を再現する最短の例です。

代わりに試みた、

  • プライムフェイス 3.5
  • プライムフェイス 4.0
  • プライムフェイス 5.0
  • プライムフェイス5.1
  • プライムフェイス5.2

PrimeFaces のこれらすべてのバージョンで、動作は一定のままです。

マネージド Bean:

@Named
@ViewScoped
public class CompositeRowKeyManagedBean extends LazyDataModel<GroupTable> implements Serializable {

    private List<GroupTable> selectedValues; // Getter & setter.
    private static final long serialVersionUID = 1L;

    public CompositeRowKeyManagedBean() {}

    private List<GroupTable> init() {
        List<GroupTable> list = new ArrayList<GroupTable>();

        GroupTablePK groupTablePK = new GroupTablePK("aaa", "ROLE_ADMIN");
        GroupTable groupTable = new GroupTable(groupTablePK);
        list.add(groupTable);

        groupTablePK = new GroupTablePK("bbb", "ROLE_USER");
        groupTable = new GroupTable(groupTablePK);
        list.add(groupTable);

        groupTablePK = new GroupTablePK("ccc", "ROLE_USER");
        groupTable = new GroupTable(groupTablePK);
        list.add(groupTable);

        groupTablePK = new GroupTablePK("ddd", "ROLE_USER");
        groupTable = new GroupTable(groupTablePK);
        list.add(groupTable);

        groupTablePK = new GroupTablePK("eee", "ROLE_USER");
        groupTable = new GroupTable(groupTablePK);
        list.add(groupTable);
        return list;
    }

    @Override
    public List<GroupTable> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
        List<GroupTable> list = init();
        setRowCount(list.size());
        return list;
    }

    @Override
    public Object getRowKey(GroupTable groupTable) {
        return groupTable != null ? groupTable.getGroupTablePK() : null;
    }

    @Override
    public GroupTable getRowData(String rowKey) {
        List<GroupTable> list = (List<GroupTable>) getWrappedData();
        System.out.println("rowKey : " + rowKey);

        for (GroupTable groupTable : list) {
            if (groupTable.getGroupTablePK().toString().equals(rowKey)) {
                return groupTable;
            }
        }

        return null;
    }

    public void onRowEdit(RowEditEvent event) {
        GroupTablePK groupTablePK = ((GroupTable) event.getObject()).getGroupTablePK();
        System.out.println("grouoId : " + groupTablePK.getGroupId() + " : userGroupId : " + groupTablePK.getUserGroupId());
    }
}

データ テーブル:

<p:dataTable var="row"
             value="#{compositeRowKeyManagedBean}"
             lazy="true"
             editable="true"
             selection="#{compositeRowKeyManagedBean.selectedValues}"
             rows="50">
    <p:column selectionMode="multiple"></p:column>

    <p:ajax event="rowEdit" listener="#{compositeRowKeyManagedBean.onRowEdit}"/>

    <p:column headerText="GroupId">
        <h:outputText value="#{row.groupTablePK.userGroupId}"/>
    </p:column>

    <p:column headerText="UserGroupId">
        <p:cellEditor>
            <f:facet name="output">
                <h:outputText value="#{row.groupTablePK.groupId}"/>
            </f:facet>
            <f:facet name="input">
                <p:inputText value="#{row.groupTablePK.groupId}"/>
            </f:facet>
        </p:cellEditor>
    </p:column>

    <p:column headerText="Edit">
        <p:rowEditor/>
    </p:column>
</p:dataTable>

行を編集しようとすると、onRowEdit()メソッドが呼び出されます。はgetRowData()2 回呼び出され、前述のように、後続の 2 つの呼び出しで行キーの分割を生成します。


これらは 2 つのドメイン クラスGroupTableGroupTablePK.

public class GroupTable implements Serializable {

    private static final long serialVersionUID = 1L;
    protected GroupTablePK groupTablePK;

    public GroupTable() {}

    public GroupTable(GroupTablePK groupTablePK) {
        this.groupTablePK = groupTablePK;
    }

    public GroupTable(String userGroupId, String groupId) {
        this.groupTablePK = new GroupTablePK(userGroupId, groupId);
    }

    public GroupTablePK getGroupTablePK() {
        return groupTablePK;
    }

    public void setGroupTablePK(GroupTablePK groupTablePK) {
        this.groupTablePK = groupTablePK;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (groupTablePK != null ? groupTablePK.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof GroupTable)) {
            return false;
        }
        GroupTable other = (GroupTable) object;
        if ((this.groupTablePK == null && other.groupTablePK != null) || (this.groupTablePK != null && !this.groupTablePK.equals(other.groupTablePK))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entity.GroupTable[ groupTablePK=" + groupTablePK + " ]";
    }
}
public class GroupTablePK implements Serializable {

    private String userGroupId;
    private String groupId;

    public GroupTablePK() {}

    public GroupTablePK(String userGroupId, String groupId) {
        this.userGroupId = userGroupId;
        this.groupId = groupId;
    }

    public String getUserGroupId() {
        return userGroupId;
    }

    public void setUserGroupId(String userGroupId) {
        this.userGroupId = userGroupId;
    }

    public String getGroupId() {
        return groupId;
    }

    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (userGroupId != null ? userGroupId.hashCode() : 0);
        hash += (groupId != null ? groupId.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof GroupTablePK)) {
            return false;
        }
        GroupTablePK other = (GroupTablePK) object;
        if ((this.userGroupId == null && other.userGroupId != null) || (this.userGroupId != null && !this.userGroupId.equals(other.userGroupId))) {
            return false;
        }
        if ((this.groupId == null && other.groupId != null) || (this.groupId != null && !this.groupId.equals(other.groupId))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "entity.GroupTablePK[ userGroupId=" + userGroupId + ", groupId=" + groupId + " ]";
    }
}
4

2 に答える 2

6

私はあなたのMCVEを実行し(それを称賛します!)、それを再現しました。行キーは、複数選択が必要な場合に対応するために、クライアント側でカンマ区切りの文字列として解釈されるようです。あなたの場合のように、単一の行キーの文字列表現にコンマが含まれている場合、これは失敗します。取得した rowkey 引数はgetRowData()、それを明確に示しています。これらは、元の値をコンマで分割した結果です。

getRowKey().toString()したがって、この問題を解決するには、 にカンマが含まれていないことを確認する必要があります。別の区切り文字を使用することをお勧めします。たとえば、アンダースコア。

@Override
public Object getRowKey(GroupTable groupTable) {
    GroupTablePK pk = groupTable != null ? groupTable.getGroupTablePK() : null;
    return pk != null ? pk.getUserGroupId() + "_" + pk.getGroupId() : null;
}
于 2015-04-30T08:05:22.420 に答える
1

あなたの質問を読んで、 getRowKey() メソッドは単一の行を一意に識別できるものを返さなければならないと推測しています。行を表す基になる JPA エンティティに、問題のない複合キー オブジェクトがあることは理解できます。私が思うに問題は、Java オブジェクトが Map 型コレクションのキーとして何かを使用することです。キー オブジェクトはオーバーロードし、メソッドequalshashCodeメソッドの適切な実装を定義する必要があります。

Primefaces はおそらく何らかの Map を使用して、キーに基づいて値を取得しているのではないかと思います。String は不変であり、equals と hashCode が適切に実装されているため、通常、String 型はオブジェクトの一意のキーとして適しています。これらはこれに適しているため、String を渡す必要がある場合はgetRowData、そのオブジェクトに対して一意の文字列を返すメソッドをいつでも提供できます。これは、たとえば、行データ オブジェクトに提供する hashCode 実装の base 64 表現である可能性があります。

String が必須パラメーターでない場合は、単純に複合キー オブジェクトに equals と hashCode を実装し、それをキーとして直接使用します。

于 2015-04-26T16:40:53.097 に答える