私のWicket+JPA / Hibernate + Springプロジェクトでは、機能の多くは受信トレイページに基づいており、多くのフィルタリングオプションを使用して(すべてを使用する必要はありません)、ユーザーは操作するオブジェクトのセットを制限できます。このフィルタリングを実装するための最良の戦略は何でしょうか?このアプリケーションの古いバージョンでは、検索クエリはSQL条件を含む文字列を連結して構築されていました。最近、JPAが提供する新しいCriteria APIについて読みました。検索文字列を操作するよりも、これをお勧めしますか?そして、これはDAOレイヤーとどのように組み合わされますか?ビジネスレイヤーでCriteria APIを使用して検索クエリを構築することは、レイヤーの分離の違反ではありませんか?
3 に答える
説明したようなクエリのフィルタリングには、条件付きクエリがサポートされているため、HibernateまたはJPA基準APIを使用することを強くお勧めします。私は通常、基準構築コードをDAOに配置し、必要なすべての(場合によってはnull)引数をそこに渡します。
Hibernate基準APIを使用したレンタカーアプリケーションの例からのDAOメソッドの例を次に示します。
public List<VehicleRentalContract> list(Long contractID,
String customerNameOrID, Date date,
String vehicleDescriptionOrRegistration) {
Criteria criteria = getSession().createCriteria(
VehicleRentalContract.class);
// contractID filter
if (contractID != null && contractID != 0) {
criteria.add(Restrictions.eq("id", contractID));
}
// customerNameOrID filter
if (customerNameOrID != null && customerNameOrID.length() > 0) {
try {
Long customerID = Long.parseLong(customerNameOrID);
criteria.add(Restrictions.eq("customer.id", customerID));
} catch (NumberFormatException e) {
// assume we have a customer name
String customerNameQuery = "%" + customerNameOrID.trim() + "%";
criteria.createAlias("customer", "customer").add(
Restrictions.or(Restrictions.like("customer.firstName",
customerNameQuery), Restrictions.like(
"customer.lastName", customerNameQuery)));
}
}
// date filter
if (date != null) {
criteria.add(Restrictions.and(
Restrictions.le("rentalPeriod.startDate", date),
Restrictions.ge("rentalPeriod.endDate", date)));
}
// vehicleDescriptionOrRegistration filter
if (vehicleDescriptionOrRegistration != null
&& vehicleDescriptionOrRegistration.length() > 0) {
String registrationQuery = "%"
+ Vehicle
.normalizeRegistration(vehicleDescriptionOrRegistration)
+ "%";
String descriptionQuery = "%"
+ vehicleDescriptionOrRegistration.trim() + "%";
criteria.createAlias("vehicle", "vehicle").add(
Restrictions.or(Restrictions.like("vehicle.registration",
registrationQuery), Restrictions.like(
"vehicle.description", descriptionQuery)));
}
List<VehicleRentalContract> contracts = criteria.list();
return contracts;
}
createAlias呼び出しは、SQLでの結合が必要な場合に使用できます。
私でさえ、HQLやSQLよりもCriteriaを使用することを好みます。プロジェクトが本番環境に入るとき、私たちが直面する主な問題はパフォーマンスであり、HQLもSQLもパフォーマンスよりもCriteriaと競合できないため、モジュール性とパフォーマンスが理由になります。
上記に加えて、DAOレイヤーはデータにアクセスするために作成され、このレイヤーは複雑なコーディングやビジネスロジックがなく、ガラスのように透明である必要がありますが、基準の場合は、ロジック(基準の作成)を記述して、オブジェクトにアクセスするためのより適切で調整された方法。したがって、私の見解では、DAOレイヤーにこれほど多くのロジックを配置することに違反はありません。
2つのアプローチ:
1 ..必要なフィルタリングの種類によっては、たとえばLuceneですべてのオブジェクトにインデックスを付けてから、検索クエリを使用してフィルタリングを実行することで、これを実現できる場合があります。たとえば、次のようなクエリを作成します。
title: "The Right Way"&mod_date:[20020101 TO 20030101]
参照: http: //lucene.apache.org/java/2_4_0/queryparsersyntax.html
2..または基準を使用して...
hibernateの新しいタイプセーフ基準APIを使用します。
非常に大きな基準を構築する1つの方法ではなく、分離された基準を使用してすべてのロジックを分離しようとします-
これら2つの組み合わせを使用すると、基準を簡単に作成できます。
インスピレーションを探すもう1つの場所は、grailsの動的ファインダーです。これは基本的に、静的な方法で達成しようとしていることです。
http://www.grails.org/doc/1.0.x/guide/single.html#5.4.1ダイナミックファインダー
レイヤーを完全に分離したい場合は、単純な文法を実装できます。次に、これを解析して、関連する基準を作成します。これにより、基礎となる基準の実装を変更できます。これが適切かどうかは、この抽象化があなたにとってどれほど重要かによって異なります。