A major new feature of Java EE 6 is JPA 2.0 and in particular the addition of the Criteria API which provides the ability to dynamically construct object-based queries.
This resolves some of the problems which arise when building dynamic native queries. The below example shows how to find customer entities with two search parameters:
The problem with the above is that it is not type safe and involves iterating over a List of Object where those Objects are themselves Object arrays. Also should Customer contain any child elements, these would have to be retrieved in a separate call.
Using the CriteriaBuilder, the same results can be achieved as shown below:
There is some type safety in the above but it can be furthered tied down by using the metamodel class for the entity, by using the metamodel class's public static members instead of text strings for the entity's attributes. The code would now look like this:
Having built metamodel classes using Maven, it's questionable whether it's a worthwhile exercise as any mistakes in the text based approach to finding attribute names should be flagged up by comprehensive unti testing.
This resolves some of the problems which arise when building dynamic native queries. The below example shows how to find customer entities with two search parameters:
public List<CustomerEntity> findCustomers(
final String firstName, final String surname) {
StringBuilder queryBuilder = new StringBuilder(
"select c from Customer where ");
List<String> paramList = new ArrayList<String>();
paramList.add(" upper(c.firstName) like '%?%'"
.replace("?", firstName.toUpperCase()));
paramList.add(" upper(c.surname) like '%?%'"
.replace("?", surname.toUpperCase()));
Iterator itr = paramList.iterator();
while(itr.hasNext()) {
queryBuilder.append(itr.next());
if (itr.hasNext()) {
queryBuilder.append(" and ");
}
}
final Query query = entityManager.createNativeQuery(
queryBuilder.toString());
List<Object> resultList = (List<Object>)query.getResultList();
// iterate, cast, populate and return a list
}
The problem with the above is that it is not type safe and involves iterating over a List of Object where those Objects are themselves Object arrays. Also should Customer contain any child elements, these would have to be retrieved in a separate call.
Using the CriteriaBuilder, the same results can be achieved as shown below:
public List<CustomerEntity> findCustomers(final String firstName, final String surname) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<CustomerEntity> query =
builder.createQuery(CustomerEntity.class);
Root<CustomerEntity> cust = query.from(CustomerEntity.class);
query.select(cust);
List<Predicate> predicateList = new ArrayList<Predicate>();
Predicate firstNamePredicate, surnamePredicate;
if ((firstName != null) && (!(firstName.isEmpty()))) {
firstNamePredicate = builder.like(
builder.upper(cust.<String>get("firstName")),
"%"+firstName.toUpperCase()+"%");
predicateList.add(firstNamePredicate);
}
if ((surname != null) && (!(surname.isEmpty()))) {
surnamePredicate = builder.like(
builder.upper(cust.<String>get("surname")),
"%"+surname.toUpperCase()+"%");
predicateList.add(surnamePredicate);
}
Predicate[] predicates = new
Predicate[predicateList.size()];
PredicateList.toArray(predicates);
query.where(predicates);
return entityManager.createQuery(query).getResultList();
}
There is some type safety in the above but it can be furthered tied down by using the metamodel class for the entity, by using the metamodel class's public static members instead of text strings for the entity's attributes. The code would now look like this:
firstNamePredicate = builder.like(
builder.upper(cust.get(CustomerEntity_.firstName)),
"%"+firstName.toUpperCase()+"%");
surnamePredicate = builder.like(
builder.upper(cust.get(CustomerEntity_.surname)),
"%"+surname.toUpperCase()+"%");
Having built metamodel classes using Maven, it's questionable whether it's a worthwhile exercise as any mistakes in the text based approach to finding attribute names should be flagged up by comprehensive unti testing.
本文介绍了 Java EE 6 中 JPA 2.0 的 Criteria API,该 API 支持动态构造类型安全的对象查询,解决了使用原生查询时的一些问题。通过对比传统字符串拼接查询的方式,展示了使用 Criteria API 实现相同功能的代码示例,并讨论了如何进一步提高类型安全性。
3019

被折叠的 条评论
为什么被折叠?



