Condições de predicado de critérios de JPA

Eu tenho o seguinte trecho de código para construir o construtor de critérios onde a condição.

Gostaria de saber se há alguma maneira de tornar isso melhor, pois eu teria mais onde as condições e as mesmas condições seriam usadas para obter a contagem de registros.

Qualquer insight é altamente apreciável

private List  getProducts(MultivaluedMap params) throws JSONException { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery  criteriaQuery = criteriaBuilder.createQuery(Product.class); Root  root = criteriaQuery.from(Product.class); List  p = new ArrayList  (); Predicate prodIdPredicate, prodNamePredicate; JSONObject inputJSON = new JSONObject(params); if (inputJSON.isNull("filter") == false) { JSONObject filter = inputJSON.getJSONObject("filter"); JSONArray filters = filter.getJSONArray("filters"); for (int i = 0; i < filters.length(); i++) { JSONObject j = (JSONObject) filters.get(i); if (j.getString("field").equals("prodId")) { prodIdPredicate = criteriaBuilder.like(root.get(Product_.prodId), j.getString("value")); p.add(prodIdPredicate); } if (j.getString("field").equals("prodName")) { prodNamePredicate = criteriaBuilder.like(root.get(Product_.prodName), j.getString("value")); p.add(prodNamePredicate); } } } Predicate[] pr = new Predicate[p.size()]; p.toArray(pr); criteriaQuery.where(pr); 

Primeiro de tudo você deve considerar reestruturar seu aplicativo de forma em camadas. Você precisa pelo menos de 3 camadas, DAO, Service e WebService.

Todas as coisas sobre database e JPA devem estar na sua camada DAO. E todas as coisas relacionadas a json devem estar na sua camada WebService. Sua camada de serviço deve gerenciar a transação e a comunicação entre o serviço da Web e a camada dao.

Primeiro, vamos falar sobre sua camada de serviço da web. Seus objects JSON provavelmente vêm de um serviço da web Restful. Como quase todas as estruturas suportam o json marshalling / unmarshalling, não é aconselhável analisar seus objects de transferência de dados manualmente. Com isso, você pode preferir declarar uma class FieldDto e passar suas instâncias ao invés de JSONObject. Aqui está um exemplo de FieldDto . É um POJO.

 public class FieldDto { private String prodId; private String prodName; // Getters & Setters etc. } 

Você pode facilmente marshall / unmarshall para json usando GSON ou Jackson. Provavelmente o framework tem um desses padrões para lidar com a conversão do json.

A próxima camada é a camada de serviço. Na camada de serviço, você gerencia suas transactions e converte seus objects DTO em algo que sua camada DAO pode entender facilmente. Nesse caso, sua camada de serviço passa os fieldDto.getProdId() e fielDto.getProdName() para a camada DAO.

Sua última camada é a camada DAO. Primeiro, vamos alterar sua assinatura de método.

 public List  getProducts(String prodId, String prodName) { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery  criteriaQuery = criteriaBuilder.createQuery(Product.class); Root  root = criteriaQuery.from(Product.class); List  p = new ArrayList  (); if(prodId != null){ p.add(criteriaBuilder.like(root.get(Product_.prodId),prodId)); } if(prodName != null){ p.add(criteriaBuilder.like(root.get(Product_.prodName), prodName)); } if(!p.isEmpty()){ Predicate[] pr = new Predicate[p.size()]; p.toArray(pr); criteriaQuery.where(pr); } return getEntityManager().createQuery(criteriaQuery).getResultList(); } 

Não é isso. Este código ainda precisa de melhorias. Em um dos meus projetos, eu criei uma API fluente para gerenciar todas as partes do clichê. Quando você começar a escrever outras classs DAO, você perceberá que alguns dos blocos de código repetem-se repetidamente.

Aqui está um exemplo de uma api fluente. Você pode querer construir sua versão dele.

 import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.PersistenceException; import javax.persistence.TypedQuery; import javax.persistence.criteria.*; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.CollectionAttribute; import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SingularAttribute; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Vector; public final class SimpleSelectBuilder { private final EntityManager entityManager; private final CriteriaBuilder criteriaBuilder; private final CriteriaQuery criteriaQuery; private final Root root; private final Collection predicates; private Integer first = null; private Integer max = null; private LockModeType lockModeType = null; public SimpleSelectBuilder(final EntityManager entityManager, final Class entityClazz) { this.entityManager = entityManager; this.criteriaBuilder = entityManager.getCriteriaBuilder(); this.criteriaQuery = this.criteriaBuilder.createQuery(entityClazz); this.root = criteriaQuery.from(entityClazz); this.predicates = new Vector<>(); } public SimpleSelectBuilder and(final Attribute attribute, final Object value) { final Expression expression = this.getExpression(attribute, root); this.predicates.add(criteriaBuilder.equal(expression, value)); return this; } public SimpleSelectBuilder andNotIn(final Attribute attribute, final Collection values) { final Expression expression = this.getExpression(attribute, root); this.predicates.add(criteriaBuilder.not(expression.in(values))); return this; } public SimpleSelectBuilder andIn(final Attribute attribute, final Collection values) { final Expression expression = this.getExpression(attribute, root); this.predicates.add(expression.in(values)); return this; } public SimpleSelectBuilder andContains(final Attribute attribute, final Object value) { final Expression expression = this.getExpression(attribute, root); this.predicates.add(criteriaBuilder.isMember(value, expression)); return this; } public SimpleSelectBuilder orderByAsc(final Attribute attribute) { final List orders = new ArrayList<>(); if (this.criteriaQuery.getOrderList() != null) { orders.addAll(this.criteriaQuery.getOrderList()); } orders.add(criteriaBuilder.asc(this.getExpression(attribute, root))); this.criteriaQuery.orderBy(orders.toArray(new Order[orders.size()])); return this; } public SimpleSelectBuilder orderByDesc(final Attribute attribute) { List orders = this.criteriaQuery.getOrderList(); if (orders == null) { orders = new ArrayList<>(); } orders.add(criteriaBuilder.desc(this.getExpression(attribute, root))); this.criteriaQuery.orderBy(orders.toArray(new Order[orders.size()])); return this; } public SimpleSelectBuilder setFirst(Integer first) { this.first = first; return this; } public SimpleSelectBuilder setMax(Integer max) { this.max = max; return this; } public SimpleSelectBuilder setLockModeType(LockModeType lockModeType) { this.lockModeType = lockModeType; return this; } public List getResultList() { final TypedQuery query = this.prepareQuery(); if (lockModeType != null) { query.setLockMode(lockModeType); } if (first != null) { query.setFirstResult(first); } if (max != null) { query.setMaxResults(max); } return query.getResultList(); } public List getCacheableResultList() { final TypedQuery query = this.prepareQuery(); if (lockModeType != null) { query.setLockMode(lockModeType); } if (first != null) { query.setFirstResult(first); } if (max != null) { query.setMaxResults(max); } query.setHint("org.hibernate.cacheable", true); query.setHint("org.hibernate.cacheMode", "NORMAL"); return query.getResultList(); } public E getSingleResult() { final TypedQuery query = this.prepareQuery(); if (lockModeType != null) { query.setLockMode(lockModeType); } return query.getSingleResult(); } public E getCacheableSingleResult() { final TypedQuery query = this.prepareQuery(); if (lockModeType != null) { query.setLockMode(lockModeType); } query.setHint("org.hibernate.cacheable", true); query.setHint("org.hibernate.cacheMode", "NORMAL"); return query.getSingleResult(); } private TypedQuery prepareQuery() { this.criteriaQuery.where(this.predicates.toArray(new Predicate[this.predicates.size()])); return this.entityManager.createQuery(criteriaQuery); } private  Expression getExpression(final Attribute attribute, final From from) { if (attribute instanceof SingularAttribute) { SingularAttribute singularAttribute = (SingularAttribute) attribute; return from.get(singularAttribute); } else if (attribute instanceof PluralAttribute) { PluralAttribute pluralAttribute = (PluralAttribute) attribute; return from.get(pluralAttribute); } else { throw new PersistenceException("Attribute type of '" + attribute + "' must be one of [SingularAttribute, PluralAttribute]."); } } private  Join getJoinExpression(final Attribute attribute, final From from) { if (attribute instanceof SingularAttribute) { final SingularAttribute singularAttribute = (SingularAttribute) attribute; return from.join(singularAttribute); } else if (attribute instanceof CollectionAttribute) { final CollectionAttribute collectionAttribute = (CollectionAttribute) attribute; return from.join(collectionAttribute); } else { throw new PersistenceException("Attribute type of '" + attribute + "' must be one of [SingularAttribute, PluralAttribute]."); } } public SimpleSelectBuilder joinAnd(final Attribute attribute, final Object value, final Attribute... joinOn) { Join tableJoin = null; for (final Attribute join : joinOn) { if (tableJoin == null) { tableJoin = this.getJoinExpression(join, root); } else { tableJoin = this.getJoinExpression(join, tableJoin); } } if (tableJoin == null) { throw new PersistenceException("SelectBuilder cannot construct your join statement"); } final Expression expression = this.getExpression(attribute, tableJoin); this.predicates.add(criteriaBuilder.equal(expression, value)); return this; } } 

Se você usar isso. Que o seu método se torne isso.

 public List  getProducts(String prodId, String prodName) { // TODO add like statement to SimpleSelectBuilder return new SimpleSelectBuilder(this.getEntityManager(), Product.class) .and(Product_.prodId, prodId)) .and(Product_.prodName, prodName)) .getResultList(); } 

Será melhor se você escrever seu próprio SimpleSelectBuilder para manipular blocos de código padrão e aumentar a capacidade de reutilização. Por exemplo, você precisa adicionar like declaração like ao código acima.

Gerenciando todas as camadas, transactions, pools de conexão, etc, vai levar muito tempo. Em vez disso, você pode querer considerar um middleware para gerenciar tudo isso para o seu. Nos meus projetos eu prefiro o Spring.