我在用着,
- JPA 2.0
- 莫哈拉 2.1.9
- JSF 组件库,Primefaces 3.5。
- MySQL 5.6.11
我在 MySQL 数据库中有一个state_table
以三列命名的表作为示例。
- state_id (BigInt)
- state_name (Varchar)
- country_id (BigInt)
state_id
是自动生成的主键,country_id
是引用country
表的主键的外键。
该表由其对应的实体类命名StateTable
,该表保存的数据显示在 PrimefacesDataTable
中<p:dataTable>...</p:dataTable>
。
列DataTable
标题包含一个可单击的排序区域,<div>
对于每个列都有一个排序方向,当单击该区域时,将呈现一个字符串,ASCENDING
或者表示排序顺序,以及一个用于过滤(搜索)的文本框,用户可以在其中输入DESCENDING
每列的搜索项。
所以最终,我在 JSF 托管 bean 中得到的是一个 List 类型,表示用户希望java.util.List<org.primefaces.model.SortMeta>
的列的排序顺序。DataTable
以及一个类型的 Map ,java.util.Map<java.lang.String, java.lang.String>
将搜索列名称表示为键,将相应列的搜索项表示为值(搜索项由用户在 的每一列的列标题上的文本框中输入DataTable
)。
简而言之,我List<SortMeta>
用于排序和Map<String, String>
过滤/搜索。
我在其中一个 DAO 中的代码在排序和过滤后获取行列表如下。
@Override
@SuppressWarnings("unchecked")
public List<StateTable> getList(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String>filters)
{
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<StateTable> criteriaQuery = criteriaBuilder.createQuery(StateTable.class);
Metamodel metamodel=entityManager.getMetamodel();
EntityType<StateTable> entityType = metamodel.entity(StateTable.class);
Root<StateTable>root=criteriaQuery.from(entityType);
Join<StateTable, Country> join = null;
//Sorting
List<Order> orders=new ArrayList<Order>();
if(multiSortMeta!=null&&!multiSortMeta.isEmpty())
{
for(SortMeta sortMeta:multiSortMeta)
{
if(sortMeta.getSortField().equalsIgnoreCase("stateId"))
{
orders.add(sortMeta.getSortOrder().equals(SortOrder.ASCENDING)?criteriaBuilder.asc(root.get(StateTable_.stateId)):criteriaBuilder.desc(root.get(StateTable_.stateId)));
}
else if(sortMeta.getSortField().equalsIgnoreCase("stateName"))
{
orders.add(sortMeta.getSortOrder().equals(SortOrder.ASCENDING)?criteriaBuilder.asc(root.get(StateTable_.stateName)):criteriaBuilder.desc(root.get(StateTable_.stateName)));
}
else if(sortMeta.getSortField().equalsIgnoreCase("country.countryName")) // Yes, Primefaces DataTable renders this ugly name in case of a nested property representing a foreign key relationship.
{
join = root.join(StateTable_.countryId, JoinType.INNER);
orders.add(sortMeta.getSortOrder().equals(SortOrder.ASCENDING)?criteriaBuilder.asc(join.get(Country_.countryName)):criteriaBuilder.desc(join.get(Country_.countryName)));
}
}
}
//Filtering/searching
List<Predicate>predicates=new ArrayList<Predicate>();
if(filters!=null&&!filters.isEmpty())
{
for(Entry<String, String>entry:filters.entrySet())
{
if(entry.getKey().equalsIgnoreCase("stateId"))
{
predicates.add(criteriaBuilder.equal(root.get(StateTable_.stateId), Long.parseLong(entry.getValue())));
}
else if(entry.getKey().equalsIgnoreCase("stateName"))
{
predicates.add(criteriaBuilder.like(root.get(StateTable_.stateName), "%"+entry.getValue()+"%"));
}
else if(entry.getKey().equalsIgnoreCase("country.countryName"))// Yes, Primefaces DataTable renders this ugly name in case of a nested property representing a foreign key relationship.
{
if(join==null)
{
join = root.join(StateTable_.countryId, JoinType.INNER);
}
predicates.add(criteriaBuilder.like(join.get(Country_.countryName), "%"+entry.getValue()+"%"));
}
}
}
if(predicates!=null&&!predicates.isEmpty())
{
criteriaQuery.where(predicates.toArray(new Predicate[0]));
}
if(orders!=null&&!orders.isEmpty())
{
criteriaQuery.orderBy(orders);
}
else
{
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(StateTable_.stateId)));
}
TypedQuery<StateTable> typedQuery = entityManager.createQuery(criteriaQuery).setFirstResult(first).setMaxResults(pageSize);
return typedQuery.getResultList();
}
这按预期工作,但可以注意到,随着数据库表中列数的增加,循环if-else if
内的梯形图可以包含许多条件检查。foreach
每列都需要对排序和搜索进行条件检查。有没有一种有效的方法来摆脱这些最终可以消除或至少最小化这个if-else if
阶梯的条件检查?
PS 对于国家/地区,我正在对countryName
(在父表中可用country
)进行排序和搜索,而不是countryId
. Join
因此,在这种情况下,我使用, 。