- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在用,
我在 MySQL 数据库中有一个名为 state_table
的表以三列为例。
state_id
是自动生成的主键,country_id
是引用 country
的主键的外键表。
此表由其对应的名为StateTable
的实体类映射并且该表保存的数据显示在 Primefaces DataTable
中, <p:dataTable>...</p:dataTable>
.
DataTable
列标题包含一个可点击的排序区域,<div>
对于具有排序方向的每一列,单击此区域时,一个字符串,ASCENDING
或 DESCENDING
呈现表示排序顺序的文本框和用于过滤(搜索)的文本框,用户可以在其中为每一列输入搜索项。
所以最终,我在 JSF 托管 bean 中得到的是一个 java.util.List<org.primefaces.model.SortMeta>
类型的列表。表示 DataTable
的列的排序顺序用户希望的。
还有一个 java.util.Map<java.lang.String, java.lang.String>
类型的 map 将搜索列名称表示为键,将相应列的搜索项表示为值(用户在 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
梯子?
附言如果是国家/地区,我正在对 countryName
进行排序和搜索(在父表 country
中可用)而不是 countryId
.因此,我正在使用 Join
, 在这种情况下。
最佳答案
如果您放弃使用 SingularAttribute
值,并确保调用方在排序/过滤字段中使用完全所需的列名称调用该方法,那么您可以通过以下方式进一步简化它重复使用迭代的排序/过滤字段作为列名,而不需要对该字段进行 if/else 检查以指定正确的列名(毕竟它实际上与排序/过滤字段名相同)。
本质上,您根本不需要在 if-else
阶梯中进行那些 equalsIgnoreCase()
检查。至于区分大小写,如果调用者做错了,就在那里修正它,而不是对调用者的错误过于宽容。
下面是重构它的方法:
/**
* @throws NullPointerException When <code>multiSortMeta</code> or <code>filters</code> argument is null.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public List<?> getList(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String> filters) {
// ...
Root<StateTable> root = criteriaQuery.from(entityType);
Join<StateTable, Country> join = root.join(StateTable_.countryId, JoinType.INNER);
List<Order> orders = new ArrayList<Order>();
for (SortMeta sortMeta : multiSortMeta) {
String[] sortField = sortMeta.getSortField().split("\\.", 2);
Path<Object> path = sortField.length == 1 ? root.get(sortField[0]) : join.get(sortField[1]);
orders.add(sortMeta.getSortOrder() == SortOrder.ASCENDING
? criteriaBuilder.asc(path)
: criteriaBuilder.desc(path));
}
List<Predicate>predicates = new ArrayList<Predicate>();
for (Entry<String, String> filter : filters.entrySet()) {
String[] filterField = filter.getKey().split("\\.", 2);
Path path = filterField.length == 1 ? root.get(filterField[0]): join.get(filterField[1]);
predicates.add(filter.getValue().matches("[0-9]+")
? criteriaBuilder.equal(path, Long.valueOf(filter.getValue()))
: criteriaBuilder.like(path, "%" + filter.getValue() + "%"));
}
// ...
}
请注意,我还修改了方法以不接受 null
作为排序和过滤元,这样您就可以安全地删除所有这些空检查。这些空检查是不必要的,因为 for
循环如果为空则无论如何都不会迭代。另请注意,如果给出数字输入,则过滤使用 CriteriaBuilder#equal()
,否则使用 like()
。我不确定这是否涵盖了您的所有情况,您可能需要对其进行更多微调。
如有必要,您可以使用以下辅助方法进一步重构 Path
的获取:
@SuppressWarnings("rawtypes")
private static Path<?> getPath(String field, Root root, Join join) {
String[] fields = field.split("\\.", 2);
return fields.length == 1 ? root.get(fields[0]): join.get(fields[1]);
}
关于java - 在基于 LazyDataModel 的排序/过滤字段创建 JPA 条件查询时摆脱 if-else 阶梯,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17261124/
我正在尝试覆盖 org.primefaces.model.LazyDataModel 类(来自 Primefaces JSF 组件库)中的 load()(抽象)方法。 但是我的 Netbeans ID
我在我的 prime faces 项目中使用 lazyDataModel 通过 prime faces dataable 查看一些惰性行为的数据,但这工作正常。我的问题是我不能在我的 bean 中循环
我正在使用 PrimeFaces LazyDataModel,它工作正常。但是,我需要在我的 Facelets 页面中添加一些高级过滤器。我不想将 PrimeFaces native 过滤器与表头中的
我有一个巨大的对象列表,每个对象都包含许多图像。我想使用延迟加载来部分获取它们。我想了解如何使用 LazyDataModel 及其工作原理。 最初我认为我必须在 LazyDataModel 中仅保存可
我正在做一个小项目,它由一个表组成,其中有 36000 条记录,我通过 DataTable Primefaces 向其显示。 首先,我遇到了分页速度问题,速度慢得令人抓狂。 我去了 Showcase
我已经实现了一个带有 primefaces 的延迟加载数据表 load(int first, int pageSize, String sortField, SortOrder sortOrder,
我有一个包含 2 列的简单惰性数据模型。第二列只有默认情况下禁用的复选框(无法单击它们)。在行选择上,我只想启用复选框 (checkbox.disabled = false) 而无需调用 load 方
我有一个基于 LazyDataModel 的 Primefaces DataTable。我成功地在表中加载数据,但无法使用 setPropertyActionListener 在对话框中显示所选项目,
在我们的项目中,我们使用 PrimeFaces 3.3 以及 OmniFaces FullAjaxExceptionHandler如 this blog 中所述. 它适用于所有 Ajax 调用,除了我
我正在使用使用 LazyDataModel 的 primefaces 4.0 数据表。我也在使用 当一行被编辑和保存时,我的数据表数据没有被更新。似乎没有在 ajax 更新上调用 LazyDataMo
到现在为止,我有一个 JSF 托管 bean,它带有 LazyDataModel看起来像下面这样。 @Controller @Scope("request") public final class S
我正在尝试实现一个延迟加载的表。我想我从演示页面和文档中获得了所有步骤,但我总是收到“未找到记录”消息。我想我已经将代码简化为最小表达,至少应该有一个记录: 表格页面:
我的问题是,在我选择了第一页上的一些项目后,如果我分页到另一页并返回,我的初始选择不会显示。我试图实现 SelectableDataModel以及使用 rowKey属性,但问题仍然存在。 这是我的测试
我在 org.primefaces.model.LazyDataModel 的实现类中注入(inject)的任何 CDI bean,结果都是 null。惰性模型实现类本身是一个范围为 @javax.f
我需要根据 PrimeFaces LazyDataModel 返回的行数来渲染一些组件. 例如,仅当关联的惰性数据模型返回至少一行时才应呈现。 ... ... ... 下面
我在用, JPA 2.0 Mojarra 2.1.9 JSF 组件库,Primefaces 3.5。 MySQL 5.6.11 我在 MySQL 数据库中有一个名为 state_table 的表以三列
我是一名优秀的程序员,十分优秀!