JPA标准谓词条件

我有以下代码片段用于构建条件构建器where条件。

想知道是否有任何方法可以使这更好,因为我会有更多的条件和相同的条件将用于获取记录的数量。

任何见解都非常值得赞赏

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); 

首先,您必须考虑以分层方式重新构建应用程序。 您至少需要3层,DAO,服务和WebService。

关于数据库和JPA的所有内容都必须在您的DAO层中。 所有与json相关的事情都必须在您的WebService层中。 您的服务层必须管理事务以及Web服务和dao层之间的通信。

首先,我们来谈谈您的Web服务层。 您的JSON对象可能来自Restful Web服务。 由于几乎所有框架都支持json编组/解组,因此手动解析数据传输对象并不明智。 我的意思是,你可能更喜欢声明一个FieldDto类并传递它的实例而不是JSONObject。 这是FieldDto一个例子。 这是一个POJO。

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

您可以使用GSON或Jackson轻松地对json进行编组/解组。 可能你的框架默认使用其中一个来处理json转换。

下一层是服务层。 在服务层中,您可以管理事务并将DTO对象转换为DAO层可以轻松理解的对象。 在这种情况下,您的服务层将fieldDto.getProdId()fielDto.getProdName()传递给DAO层。

您的最后一层是DAO图层。 首先让我们改变您的方法签名。

 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(); } 

这不是它。 此代码仍需要改进。 在我的一个项目中,我创建了一个流畅的api来管理所有的样板部件。 当你开始编写其他DAO类时,你会发现一些代码块一遍又一遍地重复。

这是一个流畅的api的例子。 您可能想要构建它的版本。

 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; } } 

如果你使用这个。 比你的方法成为这个。

 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(); } 

如果您编写自己的SimpleSelectBuilder来处理样板代码块并提高可重用性,那将会更好。 例如,您需要在上面的代码中添加like语句。

管理所有图层,事务,连接池等将花费您很多时间。 相反,您可能需要考虑使用中间件来管理所有这些。 在我的项目中,我更喜欢Spring。