如何将 where 子句添加到 Hibernate @OneToMany 显式连接 table 实体?
How to add a where clause to a Hibernate @OneToMany explicit join table entity?
给定两个实体:
Card
PurchaseProductGroup
,其中有一个 ppg_status
列(在实体上命名为 status
的字段)可以是 'A'
(活动)或 'D'
(已删除)
这些在概念上具有多对多关系,但使用了一个明确定义的名为 PurchaseProductGroupCard
的连接 table 实体(因此可以为每个映射分配一个外部 ID)。所以 Card
和 PurchaseProductGroup
都与 PurchaseProductGroupCard
有 @OneToMany
关系,例如在 Card
中有以下内容:
@OneToMany(mappedBy = "card")
private Set<PurchaseProductGroupCard> purchaseProductGroups;
这需要加以限制,以便排除状态为 'D'
的 purchaseProductGroups。一种似乎有效的方法是在 @OneToMany
:
正下方放置一个 @Where
注释
@Where(clause = "exists (select * from purchase_product_group ppg
where ppg.ppg_id = ppg_id AND ppg.ppg_status <> 'D')")
...但是有更好的方法吗?理想情况下更喜欢 Hibernate 加入 tables 并有一个像 "purchaseProduct.status <> 'D'")
.
这样的子句
我打开了 SQL 日志记录并检查了查询输出。对于上述情况是这样的:
/* load one-to-many com.prepaytec.pacasso.common.model.Card.purchaseProductGroups */
select
* /* the actual field list has been omitted for brevity */
from
pacasso.purchaseprodgrp_card purchasepr0_
inner join
pacasso.purchase_product_group purchasepr1_
on purchasepr0_.ppg_id=purchasepr1_.ppg_id
where
(
exists (
select
*
from
purchase_product_group ppg
where
ppg.ppg_id = purchasepr0_.ppg_id
AND ppg.ppg_status <> 'D'
)
)
and purchasepr0_.crd_id=?
所以必要的连接已经包括在内,它看起来就像需要的是这样的:
@Where(clause = "ppg_status <> 'D'")
然而,事实证明 不工作 因为 Hibernate 预先设置了错误的 table 别名:
where
(
purchasepr0_.ppg_status <> 'D'
)
and purchasepr0_.crd_id=?
不幸的是,一旦将别名分配给 table,就无法使用原始的 table 名称 - 因此 purchase_product_group.ppg_status <> 'D'
将不起作用。而且我不知道以编程方式确定 Hibernate 使用的别名的方法 - 所以目前的选择似乎是硬编码 Hibernate 使用的别名(即 purchasepr1_.ppg_status <> 'D'
)或使用问题中描述的 exists
方法。
更新: 进一步调查发现,对别名进行硬编码并不总是可行。这是一个条件查询,它不起作用:
/* criteria query */
select
* /* the actual field list has been omitted for brevity */
from
pacasso.merchant_acquirer this_
left outer join
pacasso.purchaseprod_merchant_acquirer purchasepr2_
on this_.mac_id=purchasepr2_.mac_id
and (
// This wouldn't work with any alias since the required
// table is pacasso.purchase_product purchasepr3_, which
// is joined below.
purchasepr2_.ppr_status <> 'D'
)
left outer join
pacasso.purchase_product purchasepr3_
on purchasepr2_.ppr_id=purchasepr3_.ppr_id
where
this_.mac_code=?
and this_.cst_id=?
最后我放弃了 @Where
方法并使用 @Filter
代替,这似乎更好,因为它可以接受 HQL 而不是数据库字段名称,并且在实体级别应用时会影响关系(不同于 @Where
)。
给定两个实体:
Card
PurchaseProductGroup
,其中有一个ppg_status
列(在实体上命名为status
的字段)可以是'A'
(活动)或'D'
(已删除)
这些在概念上具有多对多关系,但使用了一个明确定义的名为 PurchaseProductGroupCard
的连接 table 实体(因此可以为每个映射分配一个外部 ID)。所以 Card
和 PurchaseProductGroup
都与 PurchaseProductGroupCard
有 @OneToMany
关系,例如在 Card
中有以下内容:
@OneToMany(mappedBy = "card")
private Set<PurchaseProductGroupCard> purchaseProductGroups;
这需要加以限制,以便排除状态为 'D'
的 purchaseProductGroups。一种似乎有效的方法是在 @OneToMany
:
@Where
注释
@Where(clause = "exists (select * from purchase_product_group ppg
where ppg.ppg_id = ppg_id AND ppg.ppg_status <> 'D')")
...但是有更好的方法吗?理想情况下更喜欢 Hibernate 加入 tables 并有一个像 "purchaseProduct.status <> 'D'")
.
我打开了 SQL 日志记录并检查了查询输出。对于上述情况是这样的:
/* load one-to-many com.prepaytec.pacasso.common.model.Card.purchaseProductGroups */
select
* /* the actual field list has been omitted for brevity */
from
pacasso.purchaseprodgrp_card purchasepr0_
inner join
pacasso.purchase_product_group purchasepr1_
on purchasepr0_.ppg_id=purchasepr1_.ppg_id
where
(
exists (
select
*
from
purchase_product_group ppg
where
ppg.ppg_id = purchasepr0_.ppg_id
AND ppg.ppg_status <> 'D'
)
)
and purchasepr0_.crd_id=?
所以必要的连接已经包括在内,它看起来就像需要的是这样的:
@Where(clause = "ppg_status <> 'D'")
然而,事实证明 不工作 因为 Hibernate 预先设置了错误的 table 别名:
where
(
purchasepr0_.ppg_status <> 'D'
)
and purchasepr0_.crd_id=?
不幸的是,一旦将别名分配给 table,就无法使用原始的 table 名称 - 因此 purchase_product_group.ppg_status <> 'D'
将不起作用。而且我不知道以编程方式确定 Hibernate 使用的别名的方法 - 所以目前的选择似乎是硬编码 Hibernate 使用的别名(即 purchasepr1_.ppg_status <> 'D'
)或使用问题中描述的 exists
方法。
更新: 进一步调查发现,对别名进行硬编码并不总是可行。这是一个条件查询,它不起作用:
/* criteria query */
select
* /* the actual field list has been omitted for brevity */
from
pacasso.merchant_acquirer this_
left outer join
pacasso.purchaseprod_merchant_acquirer purchasepr2_
on this_.mac_id=purchasepr2_.mac_id
and (
// This wouldn't work with any alias since the required
// table is pacasso.purchase_product purchasepr3_, which
// is joined below.
purchasepr2_.ppr_status <> 'D'
)
left outer join
pacasso.purchase_product purchasepr3_
on purchasepr2_.ppr_id=purchasepr3_.ppr_id
where
this_.mac_code=?
and this_.cst_id=?
最后我放弃了 @Where
方法并使用 @Filter
代替,这似乎更好,因为它可以接受 HQL 而不是数据库字段名称,并且在实体级别应用时会影响关系(不同于 @Where
)。