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是会话级的过滤器,能对所有查询(包括关联查询)生效:
- 在
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; }
- 在会话中启用过滤器(可通过拦截器或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
相关产品推荐
相关产品推荐

