父类@Where(clause = "DELETE_FLAG='N'")注解不生效,子类添加则正常
这个问题我之前也碰到过,其实是Hibernate对@Where注解在@MappedSuperclass父类上的继承处理规则导致的——默认情况下,@Where不会从@MappedSuperclass传递到子类实体,所以你在父类加了注解没效果,子类加就正常。下面给你几个可行的解决方案:
方案一:用@FilterDef+@Filter实现全局过滤(推荐)
@Filter注解是可以通过@MappedSuperclass继承的,我们可以在父类定义全局过滤器,所有子类自动生效:
1. 修改抽象父类代码
@Data @MappedSuperclass @EntityListeners(AuditingEntityListener.class) // 定义过滤器参数 @FilterDef(name = "deletedFilter", parameters = @ParamDef(name = "deleteFlag", type = "string")) // 指定过滤条件 @Filter(name = "deletedFilter", condition = "DELETE_FLAG = :deleteFlag") public abstract class AuditedEntity extends BaseEntity { @CreatedBy private String createUserId; @CreatedDate private Date createTime; @LastModifiedBy private String lastModifyUserId; @LastModifiedDate private Date lastModifyTime; // 给默认值,避免null导致过滤失效 private String deleteFlag = "N"; }
2. 启用全局过滤器
在Spring Boot中,我们可以通过配置类全局启用这个过滤器,确保所有查询都自动带上过滤条件:
@Configuration public class HibernateFilterConfig { @Autowired private EntityManagerFactory entityManagerFactory; @PostConstruct public void initGlobalFilters() { SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class); // 获取当前会话并启用过滤器,设置默认参数为"N" sessionFactory.getCurrentSession().enableFilter("deletedFilter").setParameter("deleteFlag", "N"); } }
或者你也可以自定义Spring Data JPA的基础Repository,在通用方法上绑定过滤器,这样更灵活:
@NoRepositoryBean public interface BaseRepository<T, ID> extends JpaRepository<T, ID> { @Override @Filter(name = "deletedFilter", condition = "DELETE_FLAG = 'N'") List<T> findAll(); @Override @Filter(name = "deletedFilter", condition = "DELETE_FLAG = 'N'") Optional<T> findById(ID id); // 其他需要过滤的查询方法也可以按此方式添加 }
之后让你的SysCategoryRepository继承这个BaseRepository即可。
方案二:修改父类为@Entity并指定继承策略
如果你的业务允许修改表结构,可以把父类的@MappedSuperclass换成@Entity,然后用@Inheritance指定继承策略,这样@Where注解会被子类继承:
@Data @Entity @Inheritance(strategy = InheritanceType.JOINED) // 或者SINGLE_TABLE,根据业务选择 @EntityListeners(AuditingEntityListener.class) @Where(clause = "DELETE_FLAG='N'") public abstract class AuditedEntity extends BaseEntity { // 字段保持不变 @CreatedBy private String createUserId; @CreatedDate private Date createTime; @LastModifiedBy private String lastModifyUserId; @LastModifiedDate private Date lastModifyTime; private String deleteFlag = "N"; }
子类的@Entity注解保持不变:
@Entity @Data @Table(name = "SYS_CATEGORY") public class SysCategoryEntity extends AuditedEntity {}
这种方式的缺点是会改变数据库表的结构(比如JOINED策略会生成父类表和子类表,查询时关联),如果已有生产数据需要谨慎操作。
为什么@Where在父类不生效?
简单来说,Hibernate的@Where注解是实体级别的注解,它只会作用在直接标注的@Entity类上。而@MappedSuperclass只是用来共享字段映射,不属于实体范畴,所以父类上的@Where不会被子类继承和应用。
验证方法
修改完成后,你可以开启Hibernate的SQL日志,查看查询SysCategoryEntity时生成的SQL语句,应该会自动带上DELETE_FLAG='N'的过滤条件,说明配置生效了。
内容的提问来源于stack exchange,提问作者Belala

