问题
I love the type safety CriteriaQuery brings ing JPA 2.0 but it also brings a bit of boiler-plate code. For example, let say I have an entity called NamedEntity, which simply has an id and a String field called "name" (assume it has the unique constraint set to true). Here's what the NamedEntityManager might look like:
public class NamedEntityManager
{
//inject using your framework
EntityManager entityManager;
//retrieve all existing entities of type NamedEntity from DB
public Iterable<NamedEntity> queryAll()
{
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
return entityManager.createQuery(query).getResultList();
}
//retrieve a single entity of type NamedEntity from DB using specified name
public NamedEntity queryByName(String name)
{
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class);
Root<NamedEntity> root = query.from(NamedEntity.class);
query = query.where(root.<NamedEntity>get("name").in(name));
//skipped the try/catch block for the sake of brevity
return entityManager.createQuery(query).getSingleResult();
}
}
Is there a way to condense the code in order to avoid copying/pasting the same lines of code into each query method? Perhaps somehow reuse the CriteriaQuery object?
回答1:
I was looking for something like that, you could take a look at Querydsl (LGPL licensed) which can have JPA as backend.
Im still reading into it, but from their examples, it looks pretty clean.
HQLQuery q = new HibernateQuery(session);
QCat cat = new QCat("cat"); // query type
List<Cat> cats = q.from(cat).where(cat.name.between("A", "B")).list(cat);
回答2:
In JPA 2.1, it will most probably be possible to mix JPQL and Criterias. With such an approach you could define a base query with JPQL and then use the Criteria API to dynamically add small parts.
I figure the API will be less verbose then, since you only need to use small parts of it.
回答3:
Then Use JPA-2.0 MetaData model. http://docs.jboss.org/hibernate/jpamodelgen/1.0/reference/en-US/html_single/
回答4:
It seems there's no way to reduce the amount of code. I guess something had to be sacrificed to gain type safety.
回答5:
Way outdated, this post, but I want to add what I recently built for simple queries
public static class Jpa2Whatsoever {
private final EntityManager em;
public class Jpa2WhatsoeverProgress<T> {
private CriteriaQuery<T> cq;
private List<Predicate> predicates = new ArrayList<>();
private Root<T> root;
public Jpa2WhatsoeverProgress(Class<T> type) {
this.cq = em.getCriteriaBuilder().createQuery(type);
this.root = cq.from(type);
}
public Jpa2WhatsoeverProgress<T> where(String attributeName, Object value) {
Predicate equal = em.getCriteriaBuilder().equal(root.get(attributeName), value);
predicates.add(equal);
return this;
}
public List<T> getResultList() {
Predicate[] predicatesArray = new Predicate[predicates.size()];
TypedQuery<T> typedQuery = em.createQuery(cq.select(root).where(predicates.toArray(predicatesArray)));
List<T> resultList = typedQuery.getResultList();
return Collections.unmodifiableList(resultList);
}
}
public Jpa2Whatsoever(EntityManager entityManager) {
this.em = entityManager;
}
public <T> Jpa2WhatsoeverProgress<T> select(Class<T> type) {
return new Jpa2WhatsoeverProgress<T>(type);
}
}
You can use it like this
List<MyEntity> matchingEntities = new Jpa2Whatsoever(entityManager).select(MyEntity.class).where("id", id).where("due", new Date()).getResultList();
In the end I stopped this. Mainly because I saw that I had only two queries and I would have to extend the DSL to get the required query characteristics into it, such as
- greater than, less than
- Metamodel support
QueryBuilder.currentDate()
and alike.
Further, I find it ugly to always call where
while it actually corresponds to a more SQLly and
. Anyway, if someone is interested in a very simple query API, it is still worth a try.
BTW: Forget about the names, this was a prototype, nothing more.
来源:https://stackoverflow.com/questions/3037478/is-there-a-way-to-reduce-the-amount-of-boiler-plate-code-associated-with-a-crite