【问题标题】:Date comparision using CriteriaBuilder in java在 java 中使用 CriteriaBuilder 进行日期比较
【发布时间】:2018-12-21 09:37:09
【问题描述】:

我有当前的date(date)friday(fridayOfTheWeek)Monday(mondayOfTheWeek)。我想检查日期是否介于星期一和星期五之间。

我尝试使用谓词和获取方法,但我无法实现它

    CriteriaBuilder builder = session.getCriteriaBuilder();
    CriteriaQuery<Star> criteriaQuery = builder.createQuery(Teacher.class);
    Root<Teacher> root = criteriaQuery.from(Teacher.class);
    Join<Teacher, B> join = root.join("department").join("team");
    criteriaQuery.where(builder.equal(join.get("department"), "subject"));
   //criteriaQuery.where(builder.between(root.get("date")), MondayOfTheWeek(), FridayOfTheWeek());
    criteriaQuery.select(root);
    Query<Teacher> query = session.createQuery(criteriaQuery);

第一种方法试过了

criteriaQuery.where(builder.between(builder.function("week", Integer.class, root.get("date")), MondayOfTheWeek(), FridayOfTheWeek()));

我在builder.between上遇到的错误是

Bound mismatch: The generic method between(Expression<? extends Y>, Y, Y) of type CriteriaBuilder is not applicable for the arguments (Expression<Integer>, Date, Date). The inferred type Object&Comparable<?>&Serializable is not a valid substitute for the bounded parameter <Y extends Comparable<? super Y>>

我尝试的第二种方法是:

criteriaQuery.where(builder.between(root.get("date")), MondayOfTheWeek(), FridayOfTheWeek());

在这两者之间给出错误

The method between(Expression<? extends Y>, Expression<? extends Y>, Expression<? extends Y>) in the type CriteriaBuilder is not applicable for the arguments (Path<Object>)

我尝试的第三种方法是:

ParameterExpression<java.util.Date> parameter = builder.parameter(java.util.Date.class);
Predicate startPredicate = builder.greaterThanOrEqualTo(root.get(MondayOfTheWeek()), parameter);
Predicate endPredicate = builder.greaterThanOrEqualTo(root.get(FridayOfTheWeek()), parameter);

我得到的错误是:

The method get(SingularAttribute<? super Teacher,Y>) in the type Path<Teacher> is not applicable for the arguments (Date)

【问题讨论】:

  • 你不能用一些方法boolean isWeekday(Date date)(或者更好的boolean isWeekday(LocalDate localDate)吗?
  • 不,因为我已经有了今天的日期、星期一和星期五的日期。所以我只能使用它们来获取数据。
  • 只有当您想要获取每个(!)周的周一和周五之间的日期时,您才需要使用函数周。如果您想获取特定周的日期并且您已经计算了该特定周的星期一和星期五,那么只需使用简单的 between(root.get("date"), MondayOfTheWeek(), FridayOfTheWeek())
  • 这个方法也报错。编辑了代码并提到了上面的错误。我无法理解为什么会出现错误。
  • 请提供完整的源代码,包括类 Star、MondayOfTheWeek()、FridayOfTheWeek() 和创建 CriteriaQuery。

标签: java hibernate criteria


【解决方案1】:

选项 1. 纯 Java

您需要自己实现FunctionExpression。下面是我的自定义“包含”函数类(Sql Server 中的全文搜索)。您需要将“contains(%s,%s)”替换为“%s 和 %s 之间的 datepart(wk, %s)”,并使用 2 个属性“Expression value”而不是我的。在您的数据库文档中查找“datepart”描述。

import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.ParameterContainer;
import org.hibernate.query.criteria.internal.ParameterRegistry;
import org.hibernate.query.criteria.internal.Renderable;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.expression.LiteralExpression;
import org.hibernate.query.criteria.internal.expression.function.BasicFunctionExpression;

import javax.persistence.criteria.Expression;
import java.io.Serializable;

/**
 * Models a SQL <tt>CONTAINS</tt> expression.
 *
 * @author Steve Ebersole
 */
public class ContainsFunction extends BasicFunctionExpression<Boolean> implements Serializable {
    private final Expression<String> field;
    private final Expression<String> value;

    public ContainsFunction(CriteriaBuilderImpl criteriaBuilder, Expression<String> field, Expression<String> value) {
        super(criteriaBuilder, Boolean.class, "contains");
        this.field = field;
        this.value = value;
    }

    public ContainsFunction(
            CriteriaBuilderImpl criteriaBuilder,
            Expression<String> field,
            String value) {
        this(criteriaBuilder, field, new LiteralExpression<>(criteriaBuilder, value));
    }

    public Expression<String> getField() {
        return field;
    }

    public Expression<String> getValue() {
        return value;
    }

    public void registerParameters(ParameterRegistry registry) {
        ParameterContainer.Helper.possibleParameter(getField(), registry);
        ParameterContainer.Helper.possibleParameter(getValue(), registry);
    }


    @Override
    public String render(RenderingContext renderingContext) {
        return String.format("contains(%s,%s)=true" 
                , ((Renderable) getField()).render(renderingContext)
                , ((Renderable) getValue()).render(renderingContext));
    }
}

此自定义表达式的使用

query.where(new ContainsFunction((CriteriaBuilderImpl) builder, field, value))

选项 2.Java + DB

您可以使用CirtiaBuilder#function 方法,但它不允许在SQL datepart 函数中提供wk 常量。如果你的数据库有内置的 datapart(wk,{date}) 类比,例如 week({date}),那么你可以写

query.where(builder.between(builder.function("week", Integer.class, root.get("dateField")), first, last));

它会被翻译成SQL

week(yourTable.dateField) between ? and ?

如果你的数据库没有内置函数,你应该创建用户定义的函数。

【讨论】:

  • 是否有任何简短的方法。创建函数是一项非常耗时的任务,并且会增加代码的大小
  • 我添加了第二个选项,代码更少,但这不是纯 Java 方法。
  • 我尝试了第二个选项,但出现错误。我在上面的问题中编辑的代码中的错误和更改。请检查并帮助我。
  • datepart (wk, {date}) 返回整数 - 星期几。就像 1 - 星期一、2 - 星期二 .. 7 - 星期日(或者可能是 1 - 星期日、2 - 星期一等,取决于您的数据库设置)。所以“之间”的参数也应该是整数,但你提供日期。这就是您收到此错误的原因。
  • 不,这行不通,因为我已经有了 Date 格式的日期并且必须处理它,不能更改代码,因为它会影响项目。
【解决方案2】:

解决方案是基础:

 criteriaQuery.select(root).where(
 criteriaBuilder.greaterThanOrEqualTo(root.<Date>get("date"), MondayOfTheWeek()),
 criteriaBuilder.lessThanOrEqualTo(root.<Date>get("date"), FridayOfTheWeek()));

【讨论】:

  • 如果我不知道该值是日期类型,但可能是字符串、整数等?如何投射root.get?我试过root.&lt;clazz&gt;get() where clazz = Class&lt;?&gt;,但它没有编译。
猜你喜欢
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多