我在一个看似简单的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)]
型
3条答案
按热度按时间1aaf6o9v1#
如果您将
@Temporal
添加到Date
参数,Spring Data知道如何将该参数呈现给Hibernate,即使它是null
:字符串
(The参数的类型必须为
java.util.Date
,而不是java.sql.Date
)。“为什么SQL / Hibernate不能短路”的另一个注意事项:出于性能原因,对 predicate 重新排序是大多数数据库的一个关键特性-为此,必须首先绑定参数。大多数数据库确实会短路 predicate ,但不一定按照您将它们写入查询的顺序。
pzfprimi2#
你可以使用类型转换来解决这个日期问题。基于这个https://github.com/spring-projects/spring-data-jpa/issues/2491。提供的解决方法对我来说在5.3.28.Final的休眠版本中有效。类型转换在排序电路端和实际情况下都正常工作。
字符串
yjghlzjz3#
你在where子句的第一个条件中使用了date参数而不是实际的表字段:这应该可以工作:
字符串