Java 具有空日期参数的Hibernate本机查询

Java 具有空日期参数的Hibernate本机查询,java,database,hibernate,jpa,jakarta-ee,Java,Database,Hibernate,Jpa,Jakarta Ee,我在一个看似简单的hibernate用例上苦苦挣扎,无法弄清楚到底发生了什么: 这是我的实体: @Entity @Data @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Event { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(column

我在一个看似简单的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”可能为空:

@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);
据我所知,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);
另一个反映相同问题的错误:

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

为了确保在参数为NULL时不会计算第二个条件部分,我尝试了这种方法,使用了WHEN。。然后语法:

但是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)]

您在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);

您根本不需要检查参数是否为null,因为anything=null返回false。您只需要比较:e.date=:date或e.date=date'2000-01-01'。 无论何时传入null,第一个参数都将为false,并默认为常量比较

如果在日期参数中添加@Temporal,Spring Data知道如何将该参数呈现给Hibernate,即使该参数为null:

参数的类型必须为java.util.Date,而不是java.sql.Date


关于为什么SQL/Hibernate不能短路的另一个注意事项:出于性能原因,对谓词进行重新排序是大多数数据库的一个关键特性,要做到这一点,必须首先绑定参数。大多数数据库确实会短路谓词,但不一定按照您将它们写入查询的顺序。

您的请求在语义上是不同的。数据库中的日期字段不能为空,但存储库函数参数“日期”可以为空。这就是为什么我要测试后者的空值。这个请求和其他请求一样以sam方式崩溃。我的错。。我认为您应该考虑创建动态查询。可以将其用作参考:您的解决方案触发错误运算符不存在:date=bytea。我的问题的重点是,当我的参数为NULL时,如何避免进行这种比较,因为它不起作用。。。您是否使用spring数据jpa2??如果是这样,请使用@Nullable注释参数,这样它就不会失败。顺便提一下它也应该适用于您的第一种方法,因为它不会失败,并且:param is null将返回true。作为参考,请阅读这里是的,我是,但这不会改变任何事情。至于我的第一种方法,正如我在最初的帖子中所说的,它失败了,因为SQL条件中没有短路。因此,即使空检查有效,第二部分也会被计算。。。{date?'e.date=:date':'e.date=date'2000-01-01\}……我不知道SpEL,但看起来你不能用它做这种事情。它被设计用于解析参数的名称。您是否尝试过:Page findEventsPageable pageable、@Paramdate@Temporal java.util.Date;?这可能会触发Spring将参数设置为datenull。是的!就是这样!这是有效的:从事件e中选择e,其中DATEe.date=cast:date作为日期或cast:date作为日期为空。在日期参数上的@Temporal注释旁边。你能把这个贴出来作为答案吗?这样我就可以奖励你奖金了?谢谢
@Query(value = "SELECT e FROM Event e WHERE (case when :date is null then true else (DATE(e.date) = cast(:date AS date)) end)"
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)]
@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);
Page<Event> findEvents(Pageable pageable, @Param("date") @Temporal Date date);