我有一个惰性数据表的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;
}
}
您已经可以看到我在datatable中的每个'收据'对象与'Users'对象(类)有关系(ManyToOne)。在我添加的数据表中:
#{item.userId.name}
它可以显示收据所属的用户名。这也适用于
#{item.userId.premiumExpiresAt}
第二栏中的字段。我的问题是当我尝试对懒惰数据表中的第1列和第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)
就异常说我需要在查询中包含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;
}
我需要知道如何在带有排序/过滤的惰性数据表中使用它们时包含关系。任何有关解决问题的帮助都将不胜感激。