You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate一对一映射场景下Soft Delete失效问题咨询

Hibernate软删除@Where关联查询失效问题解答

1. 这是预期行为

Hibernate的@Where注解仅对直接查询该实体本身的场景生效,当通过关联实体(如MainEntity)进行左连接查询关联对象时,不会自动将关联实体上的@Where条件追加到主查询的过滤逻辑中。你看到的SQL里没有d.rmv=false,正是因为这个设计——@Where是实体级的过滤规则,不会自动渗透到关联查询的JOIN语句里。

2. 实现预期效果的方案

方案一:在关联字段上添加@Where注解

直接在MainEntity的detail关联字段上追加@Where注解,强制关联查询时应用软删除过滤:

@Entity
@Table(name = "main_entity")
public class MainEntity {

    @Id
    private Long id;

    @OneToOne(mappedBy = "main", cascade = CascadeType.ALL)
    @Where(clause = "rmv = false") // 新增此注解
    private DetailEntity detail;
}

这样查询MainEntity时,生成的SQL会自动带上d.rmv=false的条件。

方案二:使用@Filter全局控制软删除

相比@Where,@Filter是会话级的过滤器,能对所有查询(包括关联查询)生效:

  1. 在DetailEntity上定义过滤器:
@FilterDef(name = "softDeleteFilter", parameters = @ParamDef(name = "notDeleted", type = Boolean.class))
@Filter(name = "softDeleteFilter", condition = "rmv = :notDeleted")
@Entity
@Table(name = "detail_entity")
public class DetailEntity{
    @Id
    private Long id;

    @Column
    private Boolean rmv = false;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "main_id", nullable = false)
    private MainEntity main;
}
  1. 在会话中启用过滤器(可通过拦截器或AOP全局启用,避免重复代码):
Session session = entityManager.unwrap(Session.class);
session.enableFilter("softDeleteFilter").setParameter("notDeleted", false);

启用后,所有涉及DetailEntity的查询(包括关联查询)都会自动应用rmv=false的过滤条件。

方案三:自定义Repository查询方法

在MainEntityRepository中编写自定义查询,手动指定关联过滤条件:

public interface MainEntityRepository extends JpaRepository<MainEntity, Long> {

    @Query("SELECT m FROM MainEntity m LEFT JOIN FETCH m.detail d WHERE m.id = :id AND (d.rmv = false OR d IS NULL)")
    MainEntity findByIdWithActiveDetail(@Param("id") Long id);
}

通过这种方式可以精确控制查询逻辑,满足特定场景的需求。

内容的提问来源于stack exchange,提问作者talex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 16:44:50