java - 地图上的 Hibernate 自定义查询会生成不需要的子查询
问题描述
我有一个类购买,里面有一张地图。
@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 内的特定(KEY,VALUE)对的所有购买。特别是我想创建一个查询,它返回日期(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 上的行,以这种方式返回不止一行。关键是我不知道如何重写查询以避免这两个子查询或将 this (KEY(s) = 'READY_TO_BE_PAID') 条件放入 WHERE 子句中。我发现其他人也有同样的问题,但我找不到任何解决方案。
解决方案
我找到了解决方案!似乎当您有此查询时
SELECT p
FROM Purchase p
JOIN p.customer c
JOIN p.statusTransitions s
statusTransactions Map 的别名“s”已经是值,而不是您被引导相信的对 (KEY, VALUE)。这有点违反直觉,因为 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'已经是(键,值)对的值!
推荐阅读
- python - 为什么我的 pandas 代码会引发分配警告并运行缓慢?
- node.js - 在 BigQuery 中写入的云函数(异步函数 ...等待 bigquery ...)因未处理的拒绝/PartialFailureError 而失败?
- javascript - 如何查询 Express.js 中的特定内容?
- r - 如何过滤()包含dplyr中由文本和数字组成的列中的文本的行?
- python - 在再次打开之前关闭 Windows 程序
- angular - 如何使用ngrx中的数组更新状态
- swift - SwiftUI,仅用于容器的阴影
- connection - webRTC多点连接(3个客户端及以上)
- python - 安装和导入底图时出现问题
- c# - 如何制作一个具有 EditForm 的组件并将表单和验证封装在里面?