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
如果你使用这个。 比你的方法成为这个。
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。