グループ化および集計関数

Criteria API に簡単なリクエストを行う方法はすでに理解しました。より複雑なクエリを作成する方法を見てみましょう。

たとえば、会社の従業員数を確認するクエリを作成したいとします。HQL では次のようになります。

select count(*) from Employee

Criteria API では次のようになります。

CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));

完全な Java コードは次のようになります。

CriteriaBuilder builder = session.getCriteriaBuilder();

CriteriaQuery<Long> critQuery = builder.createQuery(Long.class);
critQuery.select(builder.count(critQuery.from(Employee.class)));

Query<Long> query = session.createQuery(critQuery);
Long count = query.getSingleResult();

HQL を使用しても同じです。

String hqlQuery = "select count(*) from Employee";

Query<Long> query = session.createQuery(hqlQuery);
Long count = query.getSingleResult();

では、社内の平均給与を計算してみましょう。HQL クエリは次のようになります。

select avg(salary) from Employee

Criteria API では次のようになります。

CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));

完全な Java コードは次のようになります。

CriteriaBuilder builder = session.getCriteriaBuilder();

CriteriaQuery<Double> critQuery = builder.createQuery(Double.class);
critQuery.select(builder.avg( critQuery.from(Employee.class).get("salary")));

Query<Double> query = session.createQuery(critQuery);
Double avgSalary = query.getSingleResult();

基準の更新

テーブルの変更は、テーブルからデータを取得するのと同じくらい簡単です。これを行うために、CriteriaBuilder にはオブジェクトを作成する特別なメソッドcreateCriteriaUpdate()があります。CriteriaUpdate<T>データベース内のエンティティを更新します。

1万未満の従業員の給料を上げましょう。この HQL クエリは次のようになります。

update Employee set salary = salary+20000 where salary<=10000

Criteria API では次のように表示されます。

CriteriaUpdate<Employee> criteriaUpdate = builder.createCriteriaUpdate(Employee.class);
Root<Employee> root = criteriaUpdate.from(Employee.class);
criteriaUpdate.set("salary", "salary+20000");
criteriaUpdate.where(builder.lt(root.get("salary"), 10000));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();

条件削除

また、レコードを削除することは、変更することよりもさらに簡単です。これを行うには、オブジェクトを作成する特別なメソッドcreateCriteriaDelete()があります。CriteriaDelete<T>

価値のない従業員を全員削減しましょう。給与が 1 万未満です。この HQL クエリは次のようになります。

delete from Employee where salary<=10000

Criteria API では次のように表示されます。

CriteriaDelete<Employee> criteriaDelete = builder.createCriteriaDelete(Employee.class);
Root<Employee> root = criteriaDelete.from(Employee.class);
criteriaDelete.where(builder.lt(root.get("salary"), 10000));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();

Criteria API の利点

それでは、Criteria API の利点は何でしょうか? クエリは面倒ですが、HQL は間違いなくよりコンパクトになります。

まず、パラメータを渡す必要がある場合、HQL クエリはそれほど短くありません。比較:

給与が 10,000 未満の従業員の数を考慮します
本社
String hqlQuery = "from Employee where salary < :sal";
Query<Employee> query = session.createQuery(hqlQuery);
query.setParametr("sal", 10000);
List<Employee> results = query.getResultList();
基準API
CriteriaBuilder builder = session.getCriteriaBuilder();
critQuery.select(critQuery.from(Employee.class)).where(builder.lt(root.get("salary"), 10000));
Query<Employee> query = session.createQuery(critQuery);
List<Employee> results = query.getResultList();

次に、クエリを動的に構築する必要がある状況が非常によくあります。たとえば、従業員、アパートなどをフィルタリングする Web ページがあるとします。そして、あるパラメータがユーザーにとって重要ではない場合、ユーザーは単にそれを示さないだけです。したがって、代わりに null がサーバーに渡されます。

あなたのタスクは次のとおりです。特定の職業 (職業)、給与 (salal)、および雇用年 (YEAR (join_date)) を持つ従業員を選択します。ただし、パラメーター値が null の場合は、フィルターでそれを使用しないでください。

その場合、HQL クエリは次のようになります。

from Employee
where (occupation = :ocp)
   	and (salary = :sal)
   	and ( YEAR(join_date) = :jny)

ただし、「jny」パラメータが null の場合、リクエストは次のようになりたいので、これは正しく機能しません。

from Employee
where (occupation = :ocp)
   	and (salary = :sal)

パラメーターを null にチェックしてリクエストを書き直すと、次のような結果が得られます。

from Employee
where (occupation = :ocp or :ocp is null)
   	and (salary = :sal or :sal is null)
   	and ( YEAR(join_date)= :jny or :jny is null)

現実がいかに複雑になっているかがわかりますか? 現実はよくこんな感じです:)

ただし、フィルターはさらに複雑になる場合があります。「購入」という単語が含まれるタスクを持つユーザーを検索してみてはいかがでしょうか。それとも期限を過ぎたタスクがあるユーザーですか?

from Employee
where (occupation = :ocp)
   	and (salary = :sal)
   	and (YEAR(join_date) = :jny)
   	and (tasks.name like '%buy%')
   	and (tasks.deadline < curdate())

このようなクエリのどこかにまたは is null と書いた場合、テーブル間の結合はキャンセルされません。

したがって、実際には、複数のテーブルのフィールドに対して複雑なフィルターを実行する場合、Criteria API が役に立ちます。だからそうなるのです。

詳細については、公式ドキュメントを参照してください。