Spring Data Rest:"Date为null"查询抛出postgres异常

use*_*077 10 postgresql hibernate jpa spring-data spring-data-rest

我使用Spring Boot和Data Rest在Java8中创建一个简单的微服务并获得postgres异常.

我的实体:

@Entity
public class ArchivedInvoice implements Serializable {
    ...
    @Column
    private String invoiceNumber;
    @Column
    private java.sql.Date invoiceDate;
    ...
}
Run Code Online (Sandbox Code Playgroud)

我的存储库界面:

@RepositoryRestResource(collectionResourceRel = "archivedinvoices", path = "archivedinvoices")
public interface ArchivedInvoiceRepository extends PagingAndSortingRepository < ArchivedInvoice, Long > {
    ...
@RestResource(rel = "findByXYZ", path = "findByXYZ")
@Query(value = "SELECT ai FROM #{#entityName} ai WHERE "
        + "(:invoiceNumber IS NULL OR ai.invoiceNumber LIKE :invoiceNumber) AND "
        + "(:invoiceDate IS NULL OR ai.invoiceDate = :invoiceDate)" 
        )
public Page < ArchivedInvoice > findByXYZ(
        @Param("invoiceNumber") @Nullable String invoiceNumber,
        @Param("invoiceDate") @Nullable Date invoiceDate,
        Pageable p);
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果我调用".../findByXYZ?invoiceDate = 2016-02-22",我将收到以下错误消息:

org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
...
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
...
Caused by: org.postgresql.util.PSQLException: FEHLER: could not determine data type of parameter
Run Code Online (Sandbox Code Playgroud)

但它有效,当我删除":invoiceDate IS NULL"部分.如果invoiceDate参数为null,我该如何检查?

小智 8

我花了一些时间来研究这个,因为我真的想比较查询中的“日期为空”,这就是结果:

当您使用“ cast(foo.date as date) is null ”时,如果该字段不为空,则它可以正常工作。如果该字段为空,则抛出此异常:

org.postgresql.util.PSQLException: ERROR: cannot cast type bytea to date
Run Code Online (Sandbox Code Playgroud)

解决方案是使用coalesce:

coalesce(:date, null) is null
Run Code Online (Sandbox Code Playgroud)

无论是否有现场测试的数据,它都可以正常工作。

我的查询示例:

@Query("SELECT c "
        + " FROM Entity c "
        + " WHERE "
        + "       and ( (coalesce(:dateFrom, null) is null and coalesce(:dateUntil, null) is null) "
        + "             or ((coalesce(c.date, null) is not null) "
        + "                 and ( "
        + "                        ((coalesce(:dateFrom, null) is null and coalesce(:dateUntil, null) is not null) and c.date <= :dateUntil) "
        + "                     or ((coalesce(:dateUntil, null) is null and coalesce(:dateFrom, null) is not null) and c.date >= :dateFrom)"
        + "                     or (c.date between :dateFrom and :dateUntil)"
        + "                 )"
        + "             )"
        + "       ) "
Run Code Online (Sandbox Code Playgroud)

希望这对你有用!

  • 我喜欢 *coalesce* 解决方案;它比铸造要短一些。 (2认同)

cha*_*erb 7

我相信@Bonifacio 是正确的,因为 Postgres@Param("invoiceDate")在执行IS NULL测试时无法确定您的参数类型。我有与您类似的查询,它们在内存 H2 数据库中的行为与预期一致,但在 Postgres 集成测试中失败。

我能够通过将参数转换为日期来解决这个问题:

@Query(value = "SELECT ai FROM #{#entityName} ai WHERE "
    + "(:invoiceNumber IS NULL OR ai.invoiceNumber LIKE :invoiceNumber) AND "
    + "(cast(:invoiceDate as date) IS NULL OR ai.invoiceDate = :invoiceDate)" 
    )
Run Code Online (Sandbox Code Playgroud)


Bon*_*cio 1

当您将 JPA 与 Postgres 一起使用时,会出现一种奇怪的行为,当您想在稍后检查所需条件之前检查参数是否为 null 时,会导致错误。

发生该错误的原因是,在读取查询时,JPA 无法识别参数类型,然后在解释查询时引发错误。

解决方法是切换参数条件的位置,首先检查所需的条件是否为真,然后检查参数是否为空。

这样,JPA 将能够识别正确的参数类型,并且不会再次引发错误。

尝试以下查询并查看它是否有效:

@Query(value = "SELECT ai FROM #{#entityName} ai WHERE "
    + "(:invoiceNumber IS NULL OR ai.invoiceNumber LIKE :invoiceNumber) AND "
    + "(ai.invoiceDate = :invoiceDate OR :invoiceDate IS NULL)" 
    )
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这不起作用。但这是个好主意!谢谢! (2认同)