JPA Prefect Terms

I have the following code snippet for building a criteria builder, where is the condition.

I would like to know if there are ways to do this better, since I will have more conditions when the conditions and the same conditions will be used to get the number of records.

Any understanding is very noticeable.

private List <Product> getProducts(MultivaluedMap params) throws JSONException { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery <Product> criteriaQuery = criteriaBuilder.createQuery(Product.class); Root <Product> root = criteriaQuery.from(Product.class); List <Predicate> p = new ArrayList <Predicate> (); 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); 
+1
java json jpa criteria-api
source share
1 answer

First of all, you should consider restructuring your application on a multilevel basis. You at least need 3 levels, DAO, Service and WebService.

Everything about the database and JPA should be at your DAO level. And all json related stuff should be at your WebService level. The service tier should manage the transaction and the relationship between the web service and the dao tier.

First, let's talk about your level of web service. Your JSON objects probably come from the Restful web service. Since almost all frameworks support json marshalling / unmarshalling, it is impractical to manually analyze data transfer objects. By this, I mean, you might prefer to declare a FieldDto class and pass instances of it instead of JSONObject. The following is an example of FieldDto . This is POJO.

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

Using GSON or Jackson you can easily output / unmarshall in json. Your infrastructure probably has one of them by default for handling json conversion.

The next layer is the service level. At the service level, you manage your transactions and convert DTO objects into something that can easily understand your DAO level. In this case, your service level will fieldDto.getProdId() through fieldDto.getProdId() and fielDto.getProdName() to the DAO level.

The last layer is the DAO layer. First, let's change your method signature.

 public List <Product> getProducts(String prodId, String prodName) { CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder(); CriteriaQuery <Product> criteriaQuery = criteriaBuilder.createQuery(Product.class); Root <Product> root = criteriaQuery.from(Product.class); List <Predicate> p = new ArrayList <Predicate> (); 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(); } 

This is not true. This code still needs to be improved. In one of my projects, I create a free api to manage all the details of templates. When you start writing other DAO classes, you will realize that some of the blocks of code repeat over and over.

Here is an example of a free api. You can create your own version.

 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<E extends Entity> { private final EntityManager entityManager; private final CriteriaBuilder criteriaBuilder; private final CriteriaQuery<E> criteriaQuery; private final Root<E> root; private final Collection<Predicate> predicates; private Integer first = null; private Integer max = null; private LockModeType lockModeType = null; public SimpleSelectBuilder(final EntityManager entityManager, final Class<E> 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<E> 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<E> andNotIn(final Attribute attribute, final Collection<Object> values) { final Expression expression = this.getExpression(attribute, root); this.predicates.add(criteriaBuilder.not(expression.in(values))); return this; } public SimpleSelectBuilder<E> andIn(final Attribute attribute, final Collection<Object> values) { final Expression expression = this.getExpression(attribute, root); this.predicates.add(expression.in(values)); return this; } public SimpleSelectBuilder<E> 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<E> orderByAsc(final Attribute attribute) { final List<Order> 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<E> orderByDesc(final Attribute attribute) { List<Order> 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<E> setFirst(Integer first) { this.first = first; return this; } public SimpleSelectBuilder<E> setMax(Integer max) { this.max = max; return this; } public SimpleSelectBuilder<E> setLockModeType(LockModeType lockModeType) { this.lockModeType = lockModeType; return this; } public List<E> getResultList() { final TypedQuery<E> 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<E> getCacheableResultList() { final TypedQuery<E> 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<E> query = this.prepareQuery(); if (lockModeType != null) { query.setLockMode(lockModeType); } return query.getSingleResult(); } public E getCacheableSingleResult() { final TypedQuery<E> 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<E> prepareQuery() { this.criteriaQuery.where(this.predicates.toArray(new Predicate[this.predicates.size()])); return this.entityManager.createQuery(criteriaQuery); } private <T> Expression<T> getExpression(final Attribute attribute, final From<E, T> 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 <T> Join<E, T> getJoinExpression(final Attribute attribute, final From<E, T> 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<E> 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; } } 

If you use this. Than your method will become so.

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

It is better if you write your own SimpleSelectBuilder to process blocks of template codes and increase reuse. For example, you need to add a like operator to the code above.

Manage all layers, transactions, connection pools, etc. take a lot of time. Instead, you might want to consider middleware to manage all this for yours. In my projects, I prefer Spring.

+3
source share

All Articles