私が使っている、
- JPA2.0
- モハラ 2.1.9
- JSF コンポーネント ライブラリ、Primefaces 3.5。
- MySQL 5.6.11
state_table
例として、3 つの列で名前が付けられた MySQL データベースのテーブルがあります。
- 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 で得られるのは、ユーザーが希望する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 の 1 つのコードは次のとおりです。
@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