Neu*_*ann 3 java database hibernate jpa jakarta-ee
我在一个看似简单的休眠用例上苦苦挣扎,无法弄清楚发生了什么:
这是我的实体:
@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() {}
}
Run Code Online (Sandbox Code Playgroud)
这是我的本机查询,以 '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);
Run Code Online (Sandbox Code Playgroud)
传递给函数的日期参数已经被截断为日期(即没有小时、分钟等),但数据库条目不是,这就是我在比较的左侧部分使用 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.
Run Code Online (Sandbox Code Playgroud)
据我了解,SQL 标准不会短路条件评估,因此始终评估第二部分。另一方面,Hibernate 无法推断“日期”类型,因为它是空的,所以它作为二进制注入到请求中,因此出现错误。
我尝试了这个变体,结果相同:
@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);
Run Code Online (Sandbox Code Playgroud)
编辑: 我也试过这个:
@Query(value = "SELECT e FROM Event e WHERE :date is null or DATE(e.date) = CAST(:date AS date)")
Run Code Online (Sandbox Code Playgroud)
另一个错误反映了同样的问题:
Caused by: org.postgresql.util.PSQLException: ERROR: cannot cast type bytea to date
Run Code Online (Sandbox Code Playgroud)
编辑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)"
Run Code Online (Sandbox Code Playgroud)
但是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)]
Run Code Online (Sandbox Code Playgroud)
如果您添加@Temporal到您的Date参数,Spring Data 知道如何将该参数呈现给 Hibernate,即使它是null:
Page<Event> findEvents(Pageable pageable, @Param("date") @Temporal Date date);
Run Code Online (Sandbox Code Playgroud)
(参数的类型必须是java.util.Date,而不是java.sql.Date)。
“为什么 SQL / Hibernate 不能短路”的另一个说明:大多数数据库的一个关键特性是出于性能原因重新排序谓词 - 为此必须首先绑定参数。大多数数据库确实会短路谓词,但不一定按照您将它们写入查询的顺序。
| 归档时间: |
|
| 查看次数: |
5796 次 |
| 最近记录: |