如何使用Hibernate @Filter注解过滤@OneToMany集合(软删除场景)
解决Hibernate @Filter过滤@OneToMany软删除集合的问题
看起来你已经找对方向了!用Hibernate的@Filter来处理软删除的集合过滤确实是个不错的方案,不过可能你还漏了关键的一步——启用过滤器,因为Hibernate默认不会自动开启过滤器的。我来帮你把整个流程补全,确保你能顺利过滤掉已删除的Foo记录:
1. 先确认实体类的完整配置
你的基础配置已经有了雏形,但需要补全关联字段和枚举定义,不然@OneToMany的关联不会生效:
Foo实体类(完整版)
@Entity @FilterDef(name = "active", defaultCondition = "status = 'A'") public class Foo { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Enumerated(EnumType.STRING) private Status status; // 必须有这个关联字段,对应Bar的@OneToMany(mappedBy = "bar") @ManyToOne private Bar bar; // getters and setters } // 状态枚举 public enum Status { A, // 活跃 D // 已删除 }
Bar实体类(完整版)
@Entity public class Bar { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy = "bar") @Filter(name = "active") // 关联之前定义的"active"过滤器 private List<Foo> foos; // getters and setters }
2. 启用过滤器的几种方式
这是最关键的一步,Hibernate不会自动启用过滤器,你可以通过以下几种方式开启:
方式一:手动在Session层面启用(基础通用方式)
在你查询Bar的代码中,先获取Hibernate Session并启用过滤器:
// 如果你用的是JPA EntityManager,先转成Hibernate Session Session session = entityManager.unwrap(Session.class); // 启用名为"active"的过滤器 session.enableFilter("active"); // 之后查询Bar,它的foos集合就会自动过滤掉status != 'A'的记录 Bar bar = session.get(Bar.class, barId); // 此时bar.getFoos()只会包含活跃的Foo
方式二:自动启用过滤器(Hibernate 5.2+支持)
如果你不想每次都手动启用,可以在@Filter注解中添加autoEnable = true,让Hibernate自动开启这个过滤器:
@OneToMany(mappedBy = "bar") @Filter(name = "active", autoEnable = true) // 添加autoEnable属性 private List<Foo> foos;
这样无论你什么时候访问foos集合,过滤器都会自动生效,不用再手动调用enableFilter。
方式三:Spring环境下全局自动启用
如果你的项目用了Spring,可以通过AOP切面来全局启用过滤器,避免重复代码:
@Aspect @Component public class GlobalFilterAspect { @Autowired private EntityManager entityManager; // 匹配所有Service层方法执行前启用过滤器 @Before("execution(* com.yourproject.service..*(..))") public void enableActiveFilter() { Session session = entityManager.unwrap(Session.class); // 确保过滤器已启用(重复调用enableFilter不会有问题) session.enableFilter("active"); } }
这样所有Service方法执行时,都会自动开启"active"过滤器,所有关联的集合都会被过滤。
3. 注意事项
- 懒加载集合:如果
foos是懒加载的,过滤器会在集合被初始化(比如调用bar.getFoos().size())的时候生效,只要初始化前过滤器已经启用就没问题。 - 二级缓存:如果你的实体启用了二级缓存,Hibernate会把过滤器状态作为缓存键的一部分,不会出现缓存中包含已删除记录的情况。
- 批量查询:如果是批量查询
Bar列表,只要在查询前启用过滤器,所有返回的Bar实例的foos集合都会被过滤。
内容的提问来源于stack exchange,提问作者matthew.kempson
相关产品推荐
相关产品推荐

