jpa 带有空Date参数的Hibernate本机查询

oknwwptz  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(105)

我在一个看似简单的hibernate用例上挣扎,不知道发生了什么:
这是我的实体:

@Entity
@Data
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Event {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(columnDefinition = "timestamp without time zone", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date date;

    @Column(columnDefinition = "text")
    private String status;

    public Event() {}
}

字符串
这是我的原生查询,调用时'date'可能为NULL:

@Query(value = "SELECT e FROM Event e WHERE :date is null or DATE(e.date) = :date")
Page<Event> findEvents(Pageable pageable, @Param("date") Date date);


传递给函数的date参数已经被截断为日期(即没有小时,分钟等),但数据库条目没有,这就是为什么我在比较的左边部分使用了DATE()sql函数。
如果使用NULL日期运行,查询将崩溃并出现以下错误:

Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: date = bytea
  Indice : No operator matches the given name and argument type(s). You might need to add explicit type casts.


据我所知,SQL标准不会短路条件求值,所以第二部分总是被求值。另一方面,Hibernate无法推断'date'类型,因为它是null,所以它作为二进制注入请求,因此错误。
我尝试了这个变体,结果是一样的:

@Query(value = "SELECT e FROM Event e WHERE :date is null or DATE(e.date) = COALESCE(:date, '2000-01-01')")
Page<Event> findEvents(Pageable pageable, @Param("date") Date date);

@Query(value = "SELECT e FROM Event e WHERE :date is null or DATE(e.date) = CAST(:date AS date)")


另一个错误反映了同样的问题:

Caused by: org.postgresql.util.PSQLException: ERROR: cannot cast type bytea to date

编辑2:

为了确保第二个条件部分在参数为NULL时永远不会被求值,我尝试了这种方法,使用了 CASE WHEN .. THEN 语法:

@Query(value = "SELECT e FROM Event e WHERE (case when :date is null then true else (DATE(e.date) = cast(:date AS date)) end)"


但是Hibernate不喜欢它,我不知道为什么。

Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected AST node: case near line 1, column 30 [SELECT e FROM Event e WHERE (case when :date is null then true else (DATE(e.date) = cast(:date AS date)) end)]

1aaf6o9v

1aaf6o9v1#

如果您将@Temporal添加到Date参数,Spring Data知道如何将该参数呈现给Hibernate,即使它是null

Page<Event> findEvents(Pageable pageable, @Param("date") @Temporal Date date);

字符串
(The参数的类型必须为java.util.Date,而不是java.sql.Date)。
“为什么SQL / Hibernate不能短路”的另一个注意事项:出于性能原因,对 predicate 重新排序是大多数数据库的一个关键特性-为此,必须首先绑定参数。大多数数据库确实会短路 predicate ,但不一定按照您将它们写入查询的顺序。

pzfprimi

pzfprimi2#

你可以使用类型转换来解决这个日期问题。基于这个https://github.com/spring-projects/spring-data-jpa/issues/2491。提供的解决方法对我来说在5.3.28.Final的休眠版本中有效。类型转换在排序电路端和实际情况下都正常工作。

AND (cast(cast(:searchDateStart as text) as timestamp) is null or date_column >= cast(cast(:searchDateStart as text) as timestamp))
AND (cast(cast(:searchDateEnd as text) as timestamp) is null or date_column <= cast(cast(:searchDateEnd as text) as timestamp))

字符串

yjghlzjz

yjghlzjz3#

你在where子句的第一个条件中使用了date参数而不是实际的表字段:这应该可以工作:

@Query(value = "SELECT e FROM Event e WHERE e.date is null or DATE(e.date) = :date")
Page<Event> findEvents(Pageable pageable, @Param("date") Date date);

字符串

相关问题