Spring JPA一对一关联改造:留存连接历史且默认返回有效连接咨询
完全可以实现,根据你使用的Hibernate版本可以选择以下两种方案,均满足不需要手动查询、不需要遍历筛选集合、不需要额外定义DTO的需求:
前置调整(两种方案都需要先做)
因为要留存所有历史连接,首先调整基础配置适配一对多的业务关系:
- 去掉
accounting_connection表中business_id字段的唯一约束,新增校验保证同一商户同一时间最多一个有效连接:- PostgreSQL可创建部分唯一索引:
CREATE UNIQUE INDEX idx_business_active_connection ON accounting_connection (business_id) WHERE disconnected_at IS NULL; - MySQL可创建联合唯一索引:
UNIQUE KEY(business_id, disconnected_at),业务侧自行控制仅生成一个有效连接即可
- PostgreSQL可创建部分唯一索引:
- 修改
AccountingConnection.java的关联注解,适配多连接对应同一商户的关系:
... @JsonBackReference @ManyToOne(fetch = FetchType.LAZY) @JoinColumn( name = "business_id", referencedColumnName = "id", nullable = false ) private Business business; ...
方案1:Hibernate 6.x 最简方案(无集合、完全兼容原有用法)
直接修改Business.java的关联注解即可,字段类型、名称完全和原有逻辑一致:
... @JsonManagedReference @OneToOne(cascade = CascadeType.ALL) @JoinFormula( value = "(SELECT ac.id FROM accounting_connection ac WHERE ac.business_id = id AND ac.disconnected_at IS NULL)", referencedColumnName = "id" ) private AccountingConnection accountingConnection; ...
- 原理:
@JoinFormula会在查询Business时自动执行括号内的原生SQL,查询当前商户有效连接的ID后关联查出完整对象,全程不需要手动写查询逻辑 - 原有业务逻辑、序列化规则无需任何调整,所有历史连接都会保留在表中,仅查询
Business关联时自动过滤无效连接。
方案2:兼容Hibernate 5.x 低版本方案
如果使用旧版本Hibernate不支持@JoinFormula关联单个实体,可以用@OneToMany+@Where注解实现,对外暴露兼容的get/set方法即可:
修改Business.java代码:
... @JsonIgnore // 避免序列化整个集合 @OneToMany(mappedBy = "business", cascade = CascadeType.ALL) @Where(clause = "disconnected_at IS NULL") private List<AccountingConnection> activeConnections; @JsonManagedReference public AccountingConnection getAccountingConnection() { return activeConnections != null && !activeConnections.isEmpty() ? activeConnections.get(0) : null; } public void setAccountingConnection(AccountingConnection accountingConnection) { if (activeConnections == null) { activeConnections = new ArrayList<>(); } activeConnections.clear(); if (accountingConnection != null) { accountingConnection.setBusiness(this); activeConnections.add(accountingConnection); } } ...
- 原理:
@Where注解会在查询activeConnections时自动加过滤条件,仅返回未断开的连接,集合最多只有1个元素,不需要遍历全量历史连接 - 对外暴露的
get/setAccountingConnection方法签名和原有完全一致,原有业务代码、序列化逻辑不需要任何修改。
内容的提问来源于stack exchange,提问作者Mankind1023
相关产品推荐
相关产品推荐

