Hibernate TABLE_PER_CLASS继承下实现多对一关联的表结构方案
可行性结论
该需求完全可以实现,且不需要修改原有CREDITCARD、BANKACCOUNT两张BillingDetails层级的基础表结构。
扩展表结构设计
只需要新增独立的PURCHASE表即可,表字段分为两类:
- Purchase实体自身的业务字段:比如主键
id、交易金额amount、交易时间create_time等,完全根据业务需求定义即可 - 关联BillingDetails的路由字段:
billing_details_id:BIGINT类型,存储关联的BillingDetails记录的主键值,不区分具体是信用卡还是银行账户类型billing_details_type:TINYINT类型,存储关联的BillingDetails的类型标识,和原有联合查询里的CLAZZ_值保持一致:1代表CreditCard类型、2代表BankAccount类型
如果你使用的ID生成器能保证
CREDITCARD、BANKACCOUNT两张表的主键全局唯一(比如统一雪花ID、全局序列),可以省略billing_details_type字段,仅靠billing_details_id就能完成唯一关联。加上该字段是为了兼容跨表主键可能重复的场景,避免关联数据错乱。
核心SQL实现逻辑
原有查询BillingDetails的联合SQL逻辑可以完全复用,不需要做任何修改,关联逻辑覆盖两种常见业务场景:
- 查询指定BillingDetails下的所有Purchase记录
比如要查询id为100、类型为1(信用卡)的账单对应的所有消费记录,直接查PURCHASE表即可:SELECT * FROM PURCHASE WHERE billing_details_id = 100 AND billing_details_type = 1; -- 主键全局唯一时可省略该条件 - 分页/全量查询BillingDetails及其关联的所有Purchase记录
直接把原有BillingDetails的联合子查询作为主表,左连接PURCHASE表即可:SELECT bd.*, p.id AS purchase_id, p.amount, p.create_time FROM ( -- 原有BillingDetails联合查询逻辑完全保留,无改动 SELECT ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER, null AS ACCOUNT, null AS BANKNAME, null AS SWIFT, 1 AS CLAZZ_ FROM CREDITCARD UNION ALL SELECT id, OWNER, null AS EXPMONTH, null AS EXPYEAR, null AS CARDNUMBER, ACCOUNT, BANKNAME, SWIFT, 2 AS CLAZZ_ FROM BANKACCOUNT ) AS bd LEFT JOIN PURCHASE p ON p.billing_details_id = bd.ID AND p.billing_details_type = bd.CLAZZ_ -- 主键全局唯一时可省略该条件
如果需要在Hibernate中完成映射,使用@Any注解配置多态关联即可,不需要修改原有BillingDetails、CreditCard、BankAccount三个实体的代码,底层生成的SQL和上述逻辑完全一致。
内容的提问来源于stack exchange,提问作者rapt
相关产品推荐
相关产品推荐

