> JPA では、CriteriaQuery (Criteria とは対照的に) はアクティブなトランザクション管理を必要としないと聞きました。
そのとおりです。
コードを標準 JPA に変更すると、エンティティを選択し (INSERTING/UPDATING/DELETING ではなく)、クエリに LockMode を設定していなければ、トランザクション内で強制的に実行されるクエリはありません。
これが目的の JPQL である場合:
SELECT c
FROM Customer c JOIN c.orders o JOIN o.lineItems i
WHERE i.product.productType = 'printer'
標準的な JPA 基準のクエリ コードは次のようになります。
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Customer> cq = cb.createQuery(Customer.class);
Root<Customer> customer = cq.from(Customer.class);
Join<Customer, Order> order = customer.join(Customer_.orders); // or .join("orders")
Join<Order, Item> item = order.join(Order_.lineItems); // or .join("lineItems")
ParameterExpression<String> p = cb.parameter(String.class, "prodType");
cq.select(customer)
.where(cb.equal(item.get(Item_.product).get(Product_.productType), p));
// if you haven't generated JPA metamodel Customer_, Product_, etc,
// can replace this with
// .where(cb.equal(item.get("product").get("productType"), p));
TypedQuery<Employee> tq = em.createQuery(cq);
q.setParameter("prodType", "printer");
return q.getResultList();
少し醜いですが、強く型付けされ (JPQL はそうではありません)、標準で、オブジェクト指向で、初期化時にコンパイルされるため高速です。:-)