Jsf 当存在将多个列组合为行键的复合主键时,重写/实现getRowKey()和getRowData()方法

Jsf 当存在将多个列组合为行键的复合主键时,重写/实现getRowKey()和getRowData()方法,jsf,primefaces,datatable,composite-key,lazydatamodel,Jsf,Primefaces,Datatable,Composite Key,Lazydatamodel,我在MySQL数据库中有一个表。不幸的是,GlassFish服务器中的JAAS身份验证/授权需要一个复合主键 mysql>desc group_表; +---------------+--------------+------+-----+---------+-------+ |字段|类型|空|键|默认|额外| +---------------+--------------+------+-----+---------+-------+ |用户|组| id | varchar(176)| NO

我在MySQL数据库中有一个表。不幸的是,GlassFish服务器中的JAAS身份验证/授权需要一个复合主键

mysql>desc group_表;
+---------------+--------------+------+-----+---------+-------+
|字段|类型|空|键|默认|额外|
+---------------+--------------+------+-----+---------+-------+
|用户|组| id | varchar(176)| NO | PRI | NULL ||
|组id | varchar(15)| NO | PRI | NULL ||
+---------------+--------------+------+-----+---------+-------+
一组2行(0.05秒)
该表包含以下格式的数据

mysql>从组_表中选择*;
+-------------------------+------------+
|用户组id |组id|
+-------------------------+------------+
| you123@gmail.com|角色(管理)|
| you123@gmail.com|角色_用户|
| you123@ymail.com|角色_用户|
| you123@hotmail.com|角色_用户|
| you123@yahoo.com|角色_用户|
+-------------------------+------------+
一组5行(0.00秒)
lazy
设置为
false
时,带有
rowKey
可以正常工作

<p:dataTable rowKey="#{row.groupTablePK.userGroupId} #{row.groupTablePK.groupId}">
    ...
</p:dataTable>
上面的实现是不完整的

使用这些实现在
中选择行时,
getRowData()
方法中的
sout
语句显示以下内容

Info:  rowKey : entity.GroupTablePK[ userGroupId=you123@gmail.com
Info:  rowKey : groupId=ROLE_USER ]
getRowKey()
方法返回
GroupTablePK
的实例,但是
getRowData()
方法只接受字符串类型的参数。它不是表示复合主键的对象(因此
GroupTablePK
),因此可以将其类型转换为适当的对象类型(
GroupTablePK
),并基于该类型可以从给定的
列表中获取
GroupTable
的实例,并获取
getRowData()
方法返回
GroupTable
的实例

如何进一步进行


这个问题纯粹是基于上一个问题:


编辑:

除了
GroupTablePK
中的
toString()
之外,我还有
hashcode()
equals()
实现。
GroupTablePK
中的
toString()
方法返回
return”实体
但是当选择
中的一行时,
getRowData()
方法会被调用两次。它在两个后续调用中以两部分返回
GroupTablePK
的字符串表示形式。在第一次调用中,它返回
entity.GroupTablePK[userGroupId=aaa
,然后在第二次调用中,它返回
groupId=ROLE\u USER]

它应该在一次调用中立即返回
entity.GroupTablePK[userGroupId=aaa,groupId=ROLE\u USER]


因此,这种比较
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;
}

通过阅读您的问题,我猜测getRowKey()方法必须返回对单行唯一可识别的内容。可以理解,表示行的底层JPA实体有一个复合键对象,这很好。我认为问题在于,对于Java对象来说,要在映射类型集合中使用任何键,键对象必须重载并为
equals
hashCode
方法定义适当的实现

我怀疑Primefaces可能正在使用某种映射来检索基于键的值。字符串类型通常是对象唯一键的最佳候选,因为字符串是不可变的,并且具有equals和hashCode的正确实现。它们是一个很好的候选者,因此,如果必须将字符串传递给
getRowData
,则始终可以在该对象上提供一个方法,为该对象返回唯一的字符串。例如,这可能是为行数据对象提供的hashCode实现的base 64表示形式

如果字符串不是必需的参数,那么只需为复合键对象实现equals和hashCode,并将其直接用作键。

我运行了您的MCVE(很荣幸!)并复制了它。在客户端,rowkey似乎被解释为逗号分隔的字符串,以涵盖需要多个选择时的情况。如果单个行键的字符串表示形式包含逗号(如您的情况),则此操作将失败。您在
getRowData()
中得到的rowkey参数就是它的明显证据:它们是原始值以逗号分隔时的结果

因此,要解决这个问题,您需要确保
getRowKey().toString()
在任何地方都不包含逗号。最好使用不同的分隔符字符。例如下划线

@Override
public Object getRowKey(GroupTable groupTable) {
    GroupTablePK pk = groupTable != null ? groupTable.getGroupTablePK() : null;
    return pk != null ? pk.getUserGroupId() + "_" + pk.getGroupId() : null;
}

当选择一行时,
getRowData()
方法被调用两次。第一次,它生成实体.GroupTablePK[userGroupId=DDDDDDDDD
,然后生成
groupId=ROLE\u USER]
——由
sout
语句生成的日志
INFO
。因此,在这种情况下,
toString()
实现在某种程度上似乎也不合理。如果您的toString()实现对于给定对象是唯一的,那么它应该是一个完美的键。如果没有,那么听起来您的
getwrappedata
方法可能有问题。你能编辑你的问题并提供代码吗?该方法属于。它是所讨论的托管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>
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 + " ]";
    }
}
@Override
public Object getRowKey(GroupTable groupTable) {
    GroupTablePK pk = groupTable != null ? groupTable.getGroupTablePK() : null;
    return pk != null ? pk.getUserGroupId() + "_" + pk.getGroupId() : null;
}