У меня есть класс Покупка с картой внутри.
@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'.Статус имеет относительную дату, которая является ЗНАЧЕНИЕМ карты, а сам статус является КЛЮЧОМ карты только потому, что покупка может быть в точном состоянии только один раз.Я хотел бы получить из базы данных все покупки с определенным пользователем (имя пользователя, которое является атрибутом пользователя) и с определенной парой (KEY, VALUE) внутри HashMap statusTransitions.В частности, я хотел бы создать запрос, который возвращает все покупки, где Date (VALUE) находится между двумя датами (fromDate и toDate), а PurchaseStatus (KEY) равен значению enum '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').Я нашел других людей, у которых была такая же проблема, но я не мог найти никакого решения.