簡體   English   中英

地圖上的休眠自定義查詢會生成不需要的子查詢

[英]Hibernate custom query on Maps generates unwanted subqueries

我有一堂課,里面有地圖。

@Entity
public class Purchase {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer purchaseId;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private User customer;

    @ManyToOne
    @JoinColumn(name = "item_id")
    private Item item;

    private String customization;

    @ElementCollection
    @MapKeyEnumerated(value = EnumType.STRING)
    @CollectionTable(name = "purchase_status")
    @MapKeyColumn(name = "status")
    @Column(name = "date")
    private Map<PurchaseStatus, Date> statusTransitions = new HashMap<>();

    private Date expectedDeliveryDate;

    @ManyToOne
    @JoinColumn(name = "purchase_cart_id")
    @JsonIgnore
    private PurchaseCart purchaseCart;

    @OneToOne
    @JoinColumn(name = "destination_address_id")
    private DestinationAddress destinationAddress;

    @Transient
    @JsonIgnore
    private Date purchaseDate;

它代表購買。 PurchaseStatus是一個枚舉器。 statusTransitions代表此購買獲得的所有狀態。 特別是可以是“ READY_TO_BE_PAID”和“ PAID”。 狀態具有它的相對日期,即地圖的VALUE,狀態本身就是地圖的KEY,因為購買只能處於一次精確的狀態。 我想從數據庫中獲取所有帶有特定用戶(用戶名,這是用戶的屬性)的購買,以及statusTransitions HashMap中具有特定(鍵,值)對的所有購買。 特別是我想創建一個查詢,該查詢返回日期(VALUE)在兩個日期(fromDate和toDate)之間並且PurchaseStatus(KEY)等於枚舉值“ READY_TO_BE_PAID”的所有購買。

我創建了這個自定義查詢:

@Query("select p from Purchase p JOIN p.customer c JOIN p.statusTransitions s WHERE c.username = :username and " +
            "(KEY(s) = 'READY_TO_BE_PAID' and " +
            "VALUE(s) >= :fromDate and " +
            "VALUE(s) <= :toDate)")
List<Purchase> findByUsernameAndByDate(@Param("fromDate") Date fromDate, @Param("toDate") Date toDate, @Param("username") String username);

唯一的問題是生成的SQL查詢如下:

select 
*
from 
  purchase purchase0_ 
    inner join user user1_ on purchase0_.customer_id=user1_.user_id 
    inner join purchase_status statustran2_ on purchase0_.purchase_id=statustran2_.purchase_purchase_id 
  where 
    statustran2_.status='READY_TO_BE_PAID' and 
    user1_.username=? and 
      (select 
        statustran2_.date 
      from 
        purchase_status statustran2_ 
      where 
        purchase0_.purchase_id=statustran2_.purchase_purchase_id
        )>=? and 
      (select 
        statustran2_.date 
      from 
        purchase_status statustran2_ 
      where 
        purchase0_.purchase_id=statustran2_.purchase_purchase_id
      )<=?

這不是我想要的。 它生成兩個子查詢,結果是拋出此錯誤:

java.sql.SQLException: Subquery returns more than 1 row

那是因為當它執行子查詢時,它不會過濾PurchaseStatus上的行,以這種方式返回的行多於一行。 關鍵是我不知道如何重寫查詢以避免這兩個子查詢或將WHERE子句放入此(KEY(s)='READY_TO_BE_PAID')條件。 我發現其他人也遇到了同樣的問題,但找不到任何解決方案。

我找到了解決方案! 看來,當您有此查詢

SELECT p 
FROM Purchase p 
    JOIN p.customer c 
    JOIN p.statusTransitions s

statusTransactions映射的別名“ s”已經是值,而不是導致您相信的對(鍵,值)。 這有點直觀,因為KEY返回鍵,但是VALUE不返回值,而是自動生成一個子查詢,這不可避免地導致您出錯。

java.sql.SQLException: Subquery returns more than 1 row

因此,正確的方式來重寫它:

SELECT p 
FROM Purchase p 
    JOIN p.customer c 
    JOIN p.statusTransitions s 
WHERE 
    c.username = :username and
    KEY(s) = 'READY_TO_BE_PAID' and
    VALUE(s) >= :fromDate and
    VALUE(s) <= :toDate

是:

SELECT p 
FROM Purchase p 
    JOIN p.customer c 
    JOIN p.statusTransitions s 
WHERE 
    c.username = :username and
    KEY(s) = 'READY_TO_BE_PAID' and
    s >= :fromDate and
    s <= :toDate

或者更緊湊:

SELECT p 
FROM Purchase p 
    JOIN p.customer c 
    JOIN p.statusTransitions s 
WHERE 
    c.username = :username and
    KEY(s) = 'READY_TO_BE_PAID' and
    s BETWEEN :fromDate and :toDate

正如我已經說過的,別名's'已經是(key,value)對的值!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM