我需要做的是使用具有多个参数的JPA标准API的搜索方法。 现在的问题是,并非每一个参数是必需的。 因此,一些可能是空的,他们不应该被包含在查询中。 我已经试过这与CriteriaBuilder,但我看不出如何使其发挥作用。
使用Hibernate的标准API,这是相当容易的。 刚创建的标准,然后添加限制。
Criteria criteria = session.createCriteria(someClass.class);
if(someClass.getName() != null) {
criteria.add(Restrictions.like("name", someClass.getName());
}
我怎么能实现与JPA的标准API一样吗?
概念是构建阵列javax.persistence.Predicate其中只包含我们要使用的谓词:
要查询示例实体:
@Entity
public class A {
@Id private Long id;
String someAttribute;
String someOtherAttribute;
...
}
查询本身:
//some parameters to your method
String param1 = "1";
String paramNull = null;
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery cq = qb.createQuery();
Root<A> customer = cq.from(A.class);
//Constructing list of parameters
List<Predicate> predicates = new ArrayList<Predicate>();
//Adding predicates in case of parameter not being null
if (param1 != null) {
predicates.add(
qb.equal(customer.get("someAttribute"), param1));
}
if (paramNull != null) {
predicates.add(
qb.equal(customer.get("someOtherAttribute"), paramNull));
}
//query itself
cq.select(customer)
.where(predicates.toArray(new Predicate[]{}));
//execute query and do something with result
em.createQuery(cq).getResultList();
看看这个网站JPA标准API 。 有很多的例子。
更新:提供一个具体的例子
让我们寻找比特定值低余额账户:
SELECT a FROM Account a WHERE a.balance < :value
首先创建一个标准生成器
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Account> accountQuery = builder.createQuery(Account.class);
Root<Account> accountRoot = accountQuery.from(Account.class);
ParameterExpression<Double> value = builder.parameter(Double.class);
accountQuery.select(accountRoot).where(builder.lt(accountRoot.get("balance"), value));
为了得到结果设置参数(S)和运行查询:
TypedQuery<Account> query = entityManager.createQuery(accountQuery);
query.setParameter(value, 1234.5);
List<Account> results = query.getResultList();
BTW:EntityManager的是在EJB /服务/ DAO的地方注射。
米克的答案漂亮的工作。 只有改变,我需要做的,是取代:
cq.select(customer).where(predicates.toArray(new Predicate[]{}));
有:
Predicate [] predicatesarr = predicates.toArray(new Predicate[predicates.size()]);
cq.select(customer).where(predicatesarr);
从某处列表阵列中的原始转换没有工作。
首先,米克的回答让我给我的答案。 给予好评了点。
我的情况是我想父/子关系,我想找到任何〜〜孩子的比赛。
员工有多个JOBTITLE(S)。
我想找到一个员工(其中有许多职称),但找到它的任何〜我送jobtitles的。
SQL会是什么样子:
SELECT * FROM dbo.EmployeeË加入dbo.JobTitle JT上e.EmployeeKey = jt.EmployeeKey WHERE(jt.JobTitleName = '程序员' OR jt.JobTitleName = 'badcop')
我扔在性别和日期的出生到完成这个例子(并给予更多的“可选”)的标准)
我的JPA代码
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
public class MyEmployeeSpecification implements Specification<MyEmployee> {
private MyEmployee filter;
public MyEmployeeSpecification(MyEmployee filter) {
super();
this.filter = filter;
}
public Predicate toPredicate(Root<MyEmployee> root, CriteriaQuery<?> cq,
CriteriaBuilder cb) {
Predicate returnPred = cb.disjunction();
List<Predicate> patientLevelPredicates = new ArrayList<Predicate>();
if (filter.getBirthDate() != null) {
patientLevelPredicates.add(
cb.equal(root.get("birthDate"), filter.getBirthDate()));
}
if (filter.getBirthDate() != null) {
patientLevelPredicates.add(
cb.equal(root.get("gender"), filter.getGender()));
}
if (null != filter.getJobTitles() && filter.getJobTitles().size() > 0) {
List<Predicate> jobTitleLevelPredicates = new ArrayList<Predicate>();
Join<JobTitle, JobTitle> hnJoin = root.join("jobtitles");
for (JobTitle hnw : filter.getJobTitles()) {
if (null != hnw) {
if (StringUtils.isNotBlank(hnw.getJobTitleName())) {
jobTitleLevelPredicates.add(cb.equal(hnJoin.get("getJobTitleName"), hnw.getFamily()));
}
}
}
patientLevelPredicates.add(cb.or(jobTitleLevelPredicates.toArray(new Predicate[]{})));
}
returnPred = cb.and(patientLevelPredicates.toArray(new Predicate[]{}));
return returnPred;
}
}
但我想我的,因为predicates.toArray(新谓词[] {}),又名时,可变参数的绝招。 (感谢米克)
我还做了“实现Specifiction”的方法。
其他有用的链接:
JPA规格通过实施例
JPA CriteriaBuilder结合标准为析取标准