java JPA Criteria Builder 中的 If/Case 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10236445/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 00:09:19  来源:igfitidea点击:

If/Case statement in JPA Criteria Builder

javajpajpa-2.0criteria-api

提问by RNJ

I want to build up a query which search dates on different entites. My structure is:

我想建立一个查询,在不同的实体上搜索日期。我的结构是:

  • Contract has date (non nullable)
  • Employee has date (non nullable)
  • Employee may have a contract id (nullable)
  • 合同有日期(不可为空)
  • 员工有日期(不可为空)
  • 员工可能有一个合同 ID(可为空)

If a Employee has a contract I want to retrieve the contract date. If an employee does not have a contract then I want to return the Employee date.

如果员工有合同,我想检索合同日期。如果员工没有合同,那么我想返回员工日期。

My code so far is:

到目前为止我的代码是:

if (inputDate!= null) {
    ParameterExpression<Date> exp = criteriaBuilder.parameter(Date.class, "inputDate");
    criteria.add(criteriaBuilder.or(
        criteriaBuilder.isNull(employee.get("contract")),
        criteriaBuilder.lessThanOrEqualTo(employee.<Date>get("creationDate"), exp),   criteriaBuilder.lessThanOrEqualTo((employee.join("contract").<Date>get("fromDate")), exp) ));}

This does not seem to work though. I always appear to go into the isNull which I do not expect.

但这似乎不起作用。我似乎总是进入我不期望的 isNull 。

I am happy to look into this some more but I guess my question is whether this is the correct way of going about it. Is it? I have seen a selectCase as well in criteriaBuilder so perhaps that may be a better solution.

我很高兴再研究一下,但我想我的问题是这是否是正确的做法。是吗?我在criteriaBuilder 中也看到了一个selectCase,所以这可能是一个更好的解决方案。

Any pointers would be greatly received.

任何指针都会受到极大的欢迎。

Thanks

谢谢

回答by JMelnik

Here would be a solution, not sure if it works, but we will manage to get it work with your help :):

这是一个解决方案,不确定它是否有效,但我们会在您的帮助下设法让它工作:):

ParameterExpression<Date> inputDateExp = criteriaBuilder.parameter(Date.class, "inputDate");
Predicate employeeCreationDate = criteriaBuilder.lessThanOrEqualTo(
        employee.<Date>get("creationDate"), inputDateExp);
Predicate contractStartDate = criteriaBuilder.lessThanOrEqualTo(
        employee.join("contract").<Date>get("fromDate"), inputDateExp);

criteria.add(
        criteriaBuilder.selectCase().when(employee.get("contract").isNull(), employeeCreationDate).otherwise(contractStartDate));

I do not understand why use "inputDate" as Expression instead of a Date? Also, I suggest renaming criteriato cand criteriaBuilderto cb, this would save space and I think it is more comfortable.

我不明白为什么使用“inputDate”作为表达式而不是日期?另外,我建议重命名criteria,以ccriteriaBuildercb,这样可节省空间,我认为这是更舒适。

回答by Patrick Garner

I think what you want to do is use Case<Date>, and use Predicateonly as first argument to Case#when. Case<Date>is an Expression<Date>, which is what you want to pass into CriteriaQuery#multiselect.

我认为您想要做的是使用Case<Date>,并且Predicate仅将其用作Case#when. Case<Date>是一个Expression<Date>,这是您想要传递的内容CriteriaQuery#multiselect

CriteriaQuery<Employee> query = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employee = query.from(Employee.class);
query.multiselect
(
    criteriaBuilder.selectCase()
        .when(criteriaBuilder.isNull(employee.get("contract")), employee.get("creationDate"))
        .otherwise(employee.join("contract").get("fromDate"))
);