Helpex - Trao đổi & giúp đỡ Đăng nhập
15

Tôi sử dụng Spring Boot và Data Rest để tạo một microservice đơn giản trong Java8 và nhận được một ngoại lệ postgres.

Thực thể của tôi:

@Entity
public class ArchivedInvoice implements Serializable {
    ...
    @Column
    private String invoiceNumber;
    @Column
    private java.sql.Date invoiceDate;
    ...
}

Giao diện kho lưu trữ của tôi:

@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);
    ...
}

Nếu tôi gọi "... / findByXYZ? ChemicalsDate = 2016-02-22", tôi sẽ nhận được thông báo lỗi sau:

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

Nhưng nó hoạt động, khi tôi loại bỏ phần ": ChemicalDate IS NULL". Làm cách nào tôi có thể kiểm tra nếu tham số ChemicalDate là null?

15 hữu ích 1 bình luận 10k xem chia sẻ
8

Tôi đã dành thời gian xem xét vấn đề này bởi vì tôi thực sự muốn so sánh "ngày là null" trong các truy vấn và đó là kết quả:

Khi bạn sử dụng " cast (foo.date as date) là null ", nó hoạt động OK nếu trường không rỗng. Nếu trường là null, ngoại lệ này sẽ được ném ra:

org.postgresql.util.PSQLException: ERROR: cannot cast type bytea to date

Giải pháp là sử dụng kết hợp:

coalesce(:date, null) is null

Nó hoạt động tốt khi có hoặc không có dữ liệu trong lĩnh vực được kiểm tra.

Ví dụ truy vấn của tôi:

@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)"
        + "                 )"
        + "             )"
        + "       ) "

Hi vọng nó sẽ giúp ích cho bạn!

8 hữu ích 1 bình luận chia sẻ
7

Tôi tin rằng @Bonifacio đúng ở chỗ Postgres không thể xác định loại @Param("invoiceDate")thông số của bạn khi thực hiện IS NULLkiểm tra. Tôi có các truy vấn tương tự như truy vấn của bạn hoạt động như mong đợi với cơ sở dữ liệu H2 trong bộ nhớ, nhưng không thành công với các bài kiểm tra tích hợp Postgres.

Tôi đã có thể giải quyết vấn đề này bằng cách truyền tham số đến một ngày như sau:

@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)" 
    )
7 hữu ích 2 bình luận chia sẻ
2

Tôi đã gặp sự cố tương tự với trường kiểu LocalDateTime và trường Dấu thời gian trong postgres 9.5. Tôi đã giải quyết nó khi chuyển đổi nó như thế này:

    @Query("SELECT c "
        + "FROM Contract c "
        + "WHERE "
        + "(:idContract IS NULL OR c.idContract = :idContract) AND "
        + "(CAST(:dtCancelInitial AS java.time.LocalDateTime) IS NULL OR (c.dtCancel >= :dtCancelInitial AND c.dtCancel < :dtCancelFinal)) "
        + "ORDER BY c.idContract")
List<Contract> findContratConsultaCancelamento(@Param("idContract") Long idContract, @Param("dtCancelInitial") LocalDateTime dtCancelInitial, @Param("dtCancelFinal") LocalDateTime dtCancelFinal);
2 hữu ích 2 bình luận chia sẻ
1

Khi bạn sử dụng JPA với Postgres, có một hành vi tò mò sẽ gây ra lỗi khi bạn muốn kiểm tra xem một tham số có rỗng hay không trước khi kiểm tra điều kiện mong muốn sau đó.

Lỗi xảy ra vì khi đọc truy vấn, JPA không thể xác định loại tham số là gì và sau đó phát sinh lỗi trong khi diễn giải truy vấn.

Cách giải quyết là chuyển đổi vị trí của các điều kiện tham số của bạn, trước tiên để kiểm tra xem điều kiện mong muốn có đúng không, sau đó kiểm tra xem tham số có rỗng hay không.

Bằng cách này, JPA sẽ có thể xác định loại tham số chính xác và lỗi sẽ không xuất hiện nữa.

Hãy thử truy vấn sau và xem nó có hoạt động không:

@Query(value = "SELECT ai FROM #{#entityName} ai WHERE "
    + "(:invoiceNumber IS NULL OR ai.invoiceNumber LIKE :invoiceNumber) AND "
    + "(ai.invoiceDate = :invoiceDate OR :invoiceDate IS NULL)" 
    )
1 hữu ích 2 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hibernate postgresql jpa spring-data spring data rest , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading