当前位置: 首页 > 知识库问答 >
问题:

带表关系的数据表排序/筛选-Eclipselink

凌永逸
2023-03-14

我有一个primefaces的惰性数据表,如下所示:

<h:form id="form">
        <p:dataTable value="#{beanReceipts.lazyModel}" paginator="true" rows="10" paginatorPosition="bottom"
                     paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
                     rowsPerPageTemplate="5,10,15" var="item" emptyMessage="#{bundle['NoData']}" reflow="true"
                     rowStyleClass="centered" styleClass="centered" lazy="true" resizableColumns="true">

            <p:column style="width:24px" styleClass="centered">
                <p:rowToggler/>
            </p:column>

            <p:column headerText="#{bundle['Name']}" filterBy="#{item.userId.name}" filterMatchMode="contains"
                      styleClass="centered" sortBy="#{item.userId.name}">
                <h:outputText value="#{item.userId.name}"/>
            </p:column>

            <p:column headerText="#{bundle['Premium']}" styleClass="centered"
                      sortBy="#{item.userId.premiumExpiresAt}">
                <p:selectBooleanCheckbox value="#{item.userId.premiumExpiresAt != null}" disabled="true"/>
            </p:column>

            <p:column headerText="#{bundle['Product']}" sortBy="#{item.productId}" styleClass="centered">
                <h:outputText value="#{item.productId}"/>
            </p:column>

            <p:column headerText="#{bundle['AutoRenew']}" sortBy="#{item.autoRenew}" styleClass="centered">
                <p:selectBooleanCheckbox value="#{item.autoRenew}" disabled="true"/>
            </p:column>

            <p:column headerText="#{bundle['ExpiresAt']}" styleClass="centered">
                <h:outputText value="#{item.expiresAt}">
                    <f:convertDateTime type="date" pattern="dd/MM/yyyy"/>
                </h:outputText>
            </p:column>

            <p:column headerText="#{bundle['PurchasedAt']}" sortBy="#{item.purchasedAt}" styleClass="centered">
                <h:outputText value="#{item.purchasedAt}">
                    <f:convertDateTime type="date" pattern="dd/MM/yyyy"/>
                </h:outputText>
            </p:column>

            <p:column headerText="#{bundle['Platform']}" sortBy="#{item.platform}" styleClass="centered">
                <h:outputText value="#{item.platform}"/>
            </p:column>

            <p:rowExpansion>
                <h:panelGrid columns="2" cellspacing="3" cellpadding="3">
                    <h:outputText value="#{bundle['OrderId']}" style="font-weight: bold"/>
                    <h:outputText value="#{item.orderId}"/>

                    <h:outputText value="#{bundle['PurchaseToken']}" style="font-weight: bold"/>
                    <h:outputText value="#{item.purchaseToken}"/>

                    <h:outputText value="#{bundle['IsProcessed']}" style="font-weight: bold"/>
                    <p:selectBooleanCheckbox value="#{item.purchasedAt != null}" disabled="true"/>

                    <h:outputText value="#{bundle['RawData']}" style="font-weight: bold"/>
                    <h:outputText value="#{item.rawData}"/>
                </h:panelGrid>

                <br/>
                <p:commandButton actionListener="#{beanReceipts.checkPaymentForUser}" icon="ui-icon-refresh"
                                 value="#{bundle['Validate']}"
                                 oncomplete="window.location.reload();" onstart="PF('loadingDia').show();"
                                 onsuccess="PF('loadingDia').hide();" style="margin: auto;display: block;"/>
            </p:rowExpansion>

            <p:column headerText="#{bundle['Options']}" styleClass="centered">
                <p:commandButton icon="ui-icon-pencil" onsuccess="PF('editdia').show();" update=":editdia"
                                 style="margin: 8px;">
                    <f:setPropertyActionListener value="#{item}" target="#{beanReceipts.editableItem}"/>
                </p:commandButton>
                <p:commandButton icon="ui-icon-trash" oncomplete="window.location.reload();"
                                 action="#{beanReceipts.deleteEntity}"
                                 onclick="if (!confirm('#{bundle['RemovePrompt']}'))return false;"
                                 style="margin: 0 auto; text-align: center;">
                    <f:setPropertyActionListener value="#{item}" target="#{beanReceipts.removableItem}"/>
                </p:commandButton>
            </p:column>

        </p:dataTable>
    </h:form>

这是我的实体类:

    public class UsersReceipts extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @Basic(optional = false)
    @Column(name = "RECEIPT_TYPE", nullable = false)
    @Enumerated(EnumType.STRING)
    private DBUserReceiptTypeEnum receiptType;

    @Column(name = "AUTO_RENEW")
    private Boolean autoRenew;

    @Column(name = "ORDER_ID", length = 255)
    private String orderId;

    @Column(name = "PRODUCT_ID", length = 255)
    private String productId;

    @Column(name = "PACKAGE_NAME", length = 255)
    private String packageName;

    @Column(name = "EXPIRES_AT")
    @Temporal(TemporalType.TIMESTAMP)
    private Date expiresAt;

    @Column(name = "PURCHASED_AT")
    @Temporal(TemporalType.TIMESTAMP)
    private Date purchasedAt;

    @Lob
    @Column(name = "PURCHASE_TOKEN", length = 65535)
    private String purchaseToken;

    @Basic(optional = false)
    @Column(name = "PLATFORM", nullable = false, length = 8)
    @Enumerated(EnumType.STRING)
    private DBAppPlatformTypeEnum platform;

    @Basic(optional = false)
    @Lob
    @Column(name = "RAW_DATA", nullable = false, length = 65535)
    private String rawData;

    @JoinColumn(name = "USER_ID", referencedColumnName = "ID", nullable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Users userId;

    public UsersReceipts() {
    }

    public UsersReceipts(Integer id) {
        this.id = id;
    }

    public UsersReceipts(Integer id, DBEntryStatusTypeEnum status, Date createdAt, DBAppPlatformTypeEnum platform,
                         DBUserReceiptTypeEnum receiptType, String rawData) {
        this.id = id;
        this.status = status;
        this.createdAt = createdAt;
        this.platform = platform;
        this.receiptType = receiptType;
        this.rawData = rawData;
    }

    public Boolean getAutoRenew() {
        return autoRenew;
    }

    public void setAutoRenew(Boolean autoRenew) {
        this.autoRenew = autoRenew;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getPackageName() {
        return packageName;
    }

    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }

    public Date getExpiresAt() {
        return expiresAt;
    }

    public void setExpiresAt(Date expiresAt) {
        this.expiresAt = expiresAt;
    }

    public Date getPurchasedAt() {
        return purchasedAt;
    }

    public void setPurchasedAt(Date purchasedAt) {
        this.purchasedAt = purchasedAt;
    }

    public String getPurchaseToken() {
        return purchaseToken;
    }

    public void setPurchaseToken(String purchaseToken) {
        this.purchaseToken = purchaseToken;
    }

    public DBAppPlatformTypeEnum getPlatform() {
        return platform;
    }

    public void setPlatform(DBAppPlatformTypeEnum platform) {
        this.platform = platform;
    }

    public DBUserReceiptTypeEnum getReceiptType() {
        return receiptType;
    }

    public void setReceiptType(DBUserReceiptTypeEnum receiptType) {
        this.receiptType = receiptType;
    }

    public String getRawData() {
        return rawData;
    }

    public void setRawData(String rawData) {
        this.rawData = rawData;
    }

    @JsonIgnore
    @XmlTransient
    public Users getUserId() {
        return userId;
    }

    public void setUserId(Users userId) {
        this.userId = userId;
    }
}

正如你已经可以看到我的每一个'收据'对象在datable有一个关系(ManyToOne)到一个'用户'对象(类)。在我的数据中,当我添加:

#{item.userId.name}

它可以显示收据所属的用户名。这也适用于

#{item.userId.premiumExpiresAt}

字段在第2列。我的问题是,当我试图排序/过滤第一和第二列在我懒惰的数据,我得到以下错误,因为关系:

SEVERE [http-nio-8080-exec-5] com.sun.faces.application.view.FaceletViewHandlingStrategy.handleRenderException Error Rendering View[/panel/receipts.xhtml]
 java.lang.IllegalArgumentException: The attribute [userId.name] is not present in the managed type [EntityTypeImpl@422737256:UsersReceipts [ javaType: class entities.UsersReceipts descriptor: RelationalDescriptor(entities.UsersReceipts --> [DatabaseTable(test_esimibul.users_receipts)]), mappings: 14]].
    at org.eclipse.persistence.internal.jpa.metamodel.ManagedTypeImpl.getAttribute(ManagedTypeImpl.java:148)
    at org.eclipse.persistence.internal.jpa.querydef.FromImpl.get(FromImpl.java:312)
    at core.AbstractFacade.getFilterCondition(AbstractFacade.java:175)
    at core.AbstractFacade.count(AbstractFacade.java:131)
    at core.panel.crud.LazyCrudBean$EntityLazyModel.load(LazyCrudBean.java:44)

由于exception说我需要在查询中包含usersId(在我的例子中是Users实体),所以我无法实现这一点。以下是我的AbstractFacade执行延迟加载的方法:

/**
     * Returns paginated, sorted and filtered result list.
     *
     * @param startingAt
     * @param maxPerPage
     * @param sortField
     * @param sortOrder
     * @param filters
     * @return
     */
    @Override
    public List<T> getAll(int startingAt, int maxPerPage, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
        EntityManager em = getEntityManager();
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<T> cq = cb.createQuery(type);
        Root<T> c = cq.from(type);
        cq.where(getFilterCondition(cb, c, filters));
        if (sortField != null) if (sortOrder == SortOrder.ASCENDING) cq.orderBy(cb.asc(c.get(sortField)));
        else if (sortOrder == SortOrder.DESCENDING) cq.orderBy(cb.desc(c.get(sortField)));
        List<T> results = em.createQuery(cq).setFirstResult(startingAt).setMaxResults(maxPerPage).getResultList();
        em.close();
        return results;
    }

    /**
     * Returns the count of rows for the given filtering criterias.
     *
     * @param filters
     * @return
     */
    @Override
    public int count(Map<String, Object> filters) {
        EntityManager em = getEntityManager();
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Long> cq = cb.createQuery(Long.class);
        Root<T> c = cq.from(type);
        cq.where(getFilterCondition(cb, c, filters));
        cq.select(cb.count(c));
        int count = em.createQuery(cq).getSingleResult().intValue();
        em.close();
        return count;
    }

/**
     * Creates a dynamic filtering condition with the given params.
     *
     * @param cb
     * @param c
     * @param filters
     * @return
     */
    private Predicate getFilterCondition(CriteriaBuilder cb, Root<T> c, Map<String, Object> filters) {
        Predicate filterCondition = cb.conjunction();
        filters.put("status", DBEntryStatusTypeEnum.ACTIVE);
        for (Map.Entry<String, Object> filter : filters.entrySet())
            if (!filter.getValue().equals(""))
                filterCondition = cb.and(filterCondition, cb.like(c.get(filter.getKey()), String.format("%%%s%%", filter.getValue())));
        return filterCondition;
    }

我需要知道在排序/过滤的惰性数据表中使用关系时如何包含它们。如果您能帮助解决这个问题,我们将不胜感激。

共有1个答案

白宏大
2023-03-14

我不确定filterBy是否适用于惰性数据表。我使用新的Primefaces 10 Datatable语法解决了一个类似的问题:

<p:datatable value="#{myView.lazymodel}" var="entry">
    <p:column field="entry.user.name"/>
    ....

这样,Primeface检测关系和过滤工作正常。

 类似资料:
  • 我有一个p:dataTable,它存储已处理表单的结果,我执行以下操作: 填充表单值。 提交。 已填充数据表--对任何列进行筛选。 更改表单值。 提交。 使用新结果填充数据表。 对任意列排序--将显示来自#3的筛选结果。 我有一个用于筛选值的arraylist,但我没有在bean中对它做任何操作。提交时,我调用actionListener,该actionListener将dataTable强制转换

  • 筛选数据 你可以通过 3 种方式筛选数据: 点击字段框中的向下箭头,然后选择“筛选”。 使用筛选窗格。 右击图表上的系列或数据点。 【提示】如果要清除筛选,则需要使用筛选窗格。 排序数据 你可以通过 2 种方式排序数据: 点击字段框中的向下箭头,然后选择“排序”。 使用排序窗格。

  • 筛选数据 你可以通过 3 种方式筛选数据: 点击字段框中的向下箭头,然后选择“筛选”。 使用筛选窗格。 按住 Control 键并点按在图表的系列或数据点。 【提示】如果要清除筛选,则需要使用筛选窗格。 排序数据 你可以通过 2 种方式排序数据: 点击字段框中的向下箭头,然后选择“排序”。 使用排序窗格。

  • 筛选数据 你可以通过 3 种方式筛选数据: 点击字段框中的向下箭头,然后选择“筛选”。 使用筛选窗格。 右击图表上的系列或数据点。 【提示】如果要清除筛选,则需要使用筛选窗格。 排序数据 你可以通过 2 种方式排序数据: 点击字段框中的向下箭头,然后选择“排序”。 使用排序窗格。

  • 如果数据源包含许多数据或字段,你可能会发现将数据或字段限制为仅所需的内容会更为容易,从而可以简化数据选择。 筛选数据 筛选窗格让你可以方便地创建和应用为数据指定的筛选条件。在工具栏点击 “筛选”来启用筛选窗格。 若要添加一个新的条件到准则,只需简单地点击 。如果你需要在括号内添加条件,点击 。 【提示】若要在现有的条件添加括号,只需简单地右击已选择的条件并选择“使用括号分组”。若要移除括号,请右击

  • 如果数据源包含许多数据或字段,你可能会发现将数据或字段限制为仅所需的内容会更为容易,从而可以简化数据选择。 筛选数据 若要添加一个新的条件到准则,只需简单地点击 来启用筛选窗格。 若要添加一个新的条件到准则,只需简单地点击 。如果你需要在括号内添加条件,点击 。 【提示】若要在现有的条件添加括号,只需简单地按住 Control 键并点按已选择的条件,然后选择“使用括号分组”。若要移除括号,请按住