带有空日期参数的java Hibernate本机查询
我在一个看似简单的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);
传递给函数的date参数已被截断为日期(即没有小时、分钟等),但数据库条目不是,这就是为什么我在比较的左侧部分使用date()sql函数
如果以空日期运行,则查询会因以下错误而崩溃:
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
EDIT2:
为了确保参数为NULL时不会计算第二个条件部分,我尝试了这种方法,使用了CASE WHEN。。然后语法:
@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)]
# 1 楼答案
您根本不需要检查参数是否为null,因为
anything = null
返回false。你只需要比较:e.date = :date or e.date = DATE('2000-01-01')
。 无论何时传入null,第一个值都将为false,并默认为常量比较# 2 楼答案
如果将
@Temporal
添加到Date
参数中,Spring Data知道如何将该参数呈现给Hibernate,即使它是null
:(参数的类型必须为
java.util.Date
,而不是java.sql.Date
)“为什么SQL/Hibernate不能短路”的另一个注释是:出于性能原因,对谓词进行重新排序是大多数数据库的一个关键特性,要做到这一点,必须首先绑定参数。大多数数据库确实会短路谓词,但不一定是按照您将它们写入查询的顺序
# 3 楼答案
您在where子句的第一个条件中使用了date参数,而不是实际的表格字段: 这应该是有效的: