I'm using,
- JPA 2.0
- Mojarra 2.1.9
- JSF component library, Primefaces 3.5.
- MySQL 5.6.11
I have a table in MySQL database named state_table
with three columns as an example.
- state_id (BigInt)
- state_name (Varchar)
- country_id (BigInt)
state_id
is a auto-generated primary key and country_id
is a foreign key that references a primary key of the country
table.
This table is mapped by its corresponding entity class named StateTable
and the data held by this table are displayed in a Primefaces DataTable
, <p:dataTable>...</p:dataTable>
.
The DataTable
column header contains a clickable sort area, <div>
for each column with a sort direction for sorting, when this area is clicked, a String, either ASCENDING
or DESCENDING
representing the sort order is rendered and a text box for filtering (searching) in which a user enters a search item for each column.
So ultimately, what I get in JSF managed bean is a List of type java.util.List<org.primefaces.model.SortMeta>
representing sort orders of the columns of the DataTable
that a user wishes.
And a Map of type java.util.Map<java.lang.String, java.lang.String>
representing the search column names as keys and search items of the corresponding columns as values (a search item is entered by a user in a text box on the column header of each column of DataTable
).
In short, I use List<SortMeta>
for sorting and Map<String, String>
for filtering/searching.
My code in one of the DAOs to get a list of rows after sorting and filtering is as follows.
@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();
}
This works as expected but as it can be noticed, the if-else if
ladder inside the foreach
loop can contain many conditional checks as the number of columns in a database table are increased.
Each column requires a conditional check for both sorting and searching. Is there an efficient way to get rid of these conditional checks that can ultimately remove or at least minimize this if-else if
ladder?
P.S. In case of country, I'm doing sorting and searching on countryName
(which is available in the parent table country
) rather than countryId
. Hence, I'm using Join
, in this case.