如何向 Hibernate @OneToMany 显式连接表实体添加 where 子句?

问题描述 投票:0回答:1

给定两个实体:

  • Card
  • PurchaseProductGroup
    ,其中有一个
    ppg_status
    列(实体上名为
    status
    的字段),可以是
    'A'
    (活动)或
    'D'
    (已删除)

这些概念上具有多对多关系,但使用了名为

PurchaseProductGroupCard
的显式定义的连接表实体(因此可以为每个映射分配一个外部 ID)。因此
Card
PurchaseProductGroup
都与
@OneToMany
具有
PurchaseProductGroupCard
关系,例如在
Card
中有以下内容:

@OneToMany(mappedBy = "card")
private Set<PurchaseProductGroupCard> purchaseProductGroups;

需要对此进行限制,以便排除状态为

'D'
的purchaseProductGroups。一种似乎有效的方法是在
@Where
:
 下方添加 
@OneToMany

注释
@Where(clause = "exists (select * from purchase_product_group ppg
                         where ppg.ppg_id = ppg_id AND ppg.ppg_status <> 'D')")

...但是有更好的方法吗?理想情况下,更喜欢 Hibernate 连接表并有一个像

"purchaseProduct.status <> 'D'"
这样的子句。

oracle hibernate join many-to-many hibernate-filters
1个回答
1
投票

我打开了 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 预先添加了错误的表别名:

where
    (
        purchasepr0_.ppg_status <> 'D'
    )
    and purchasepr0_.crd_id=?

不幸的是,一旦为表分配了别名,就无法使用原始表名称 - 因此

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
不同)。

© www.soinside.com 2019 - 2024. All rights reserved.