jsf - 覆盖/实现 getRowKey() 和 getRowData() 方法,当存在组合多列作为行键的复合主键时

标签 jsf primefaces datatable composite-key lazydatamodel

我在 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>rowKey工作正常,当 lazy设置为 false .
<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()方法只接受一个 String 类型的参数。它不是表示复合主键的对象(在此为 GroupTablePK),因此可以将其类型转换为适当的对象类型(GroupTablePK),并基于此实例 GroupTable可以从给定的 List<GroupTable> 中获得并获得 getRowData()返回 GroupTable 实例的方法.

如何进一步进行?

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

java.lang.UnsupportedOperationException: getRowData(String rowKey) must be implemented when basic rowKey algorithm is not used

编辑:

我有 hashcode()equals()除了 toString() 之外的其他实现在 GroupTablePK . toString() GroupTablePK 中的方法返回 return "entity.GroupTablePK[ userGroupId=" + userGroupId + ", groupId=" + groupId + " ]";getRowData()方法被调用两次,当 <p:dataTable> 中的一行被选中。它返回 GroupTablePK 的字符串表示在两个后续调用中分为两个部分。在第一次调用中,它返回 entity.GroupTablePK[ userGroupId=aaa然后在第二次调用中,它返回 groupId=ROLE_USER ] .

它应该返回 entity.GroupTablePK[ userGroupId=aaa, groupId=ROLE_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;
}

编辑 2:

以下是去除 JPA 噪声以重现问题的最短示例。

交替尝试,
  • PrimeFaces 3.5
  • PrimeFaces 4.0
  • PrimeFaces 5.0
  • PrimeFaces 5.1
  • PrimeFaces 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()如前所述,被调用两次并在两个后续调用中生成行键的拆分。

    这是两个域类 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 + " ]";
        }
    }
    

    最佳答案

    我运行了你的 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;
    }
    

    关于jsf - 覆盖/实现 getRowKey() 和 getRowData() 方法,当存在组合多列作为行键的复合主键时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29880155/

    相关文章:

    java - 嵌套 forEach 的 JSF JSTL 问题

    css - 如何在 JSF 中使用来自 webjars.org 的 Font Awesome

    javascript - 允许在表格刷新后输入数据表搜索按钮

    c# - “DataTable”不包含 'Columns' 的定义

    php - 数据表无法正确读取 JSON 数据

    css - 如何改变<f :facet> header?的颜色

    jsf - org.apache.commons.fileupload.servlet.ServletFileUpload.isMultipartContent(Ljakarta/servlet/http/HttpServletRequest;)Z

    jsf - 如何将 primeface 列包含到复合 Material 中

    java - 关于 JSF2 托管 Bean 作用域机制(请求作用域)的 Web 应用程序设计问题

    multithreading - 卡在 UIComponent.popComponentFromEL 的线程