首页 文章

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

提问于
浏览
0

鉴于两个实体:

  • Card

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

这些概念上具有多对多关系,但使用了明确定义的名为 PurchaseProductGroupCard 的连接表实体(因此可以为每个映射分配外部ID) . 所以 CardPurchaseProductGroupPurchaseProductGroupCard 的关系都是 @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加入表并有一个像 "purchaseProduct.status <> 'D'") 这样的子句 .

1 回答

  • 0

    我打开了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'")
    

    但是,事实证明 doesn't 作为Hibernate工作的前缀是错误的表别名:

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

    不幸的是,一旦将一个别名分配给一个表,就不可能使用原始的表名 - 所以 purchase_product_group.ppg_status <> 'D' 并不知道如何通过编程方式确定Hibernate使用的别名 - 所以目前选择似乎是要么硬编码Hibernate使用的别名(即 purchasepr1_.ppg_status <> 'D' ),要么使用问题中描述的 exists 方法 .

    UPDATE: 在进一步的调查中发现,对别名进行硬编码是不可行的:

    /* 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 不同) .

相关问题